Aims and content
The present document includes the R code to be used for implementing
the data pre-processing steps required or recommended to prepare
intensive longitudinal design (ILD) datasets for being analyzed with
multilevel and other data analysis techniques. After a few setting
procedures, the document depicts each step based on simple and commented
R code ranging from data reading to data merging, cleaning, and
centering, up to psychometric analyses and computation of the composite
scores. Then, the document include a few examples of descriptive and
inferential multilevel analyses that can be applied to investigate the
job demand-control hypotheses (Karasek, 1979) from
the pre-processed dataset. Finally, the document ends with an
illustration of how a multiverse data manipulation approach can be
applied to evaluate the robustness of the obtained findings.
The document and the included code are based on R 4.4.1, as returned
by the R.version command below. To get start with R, we
recommend Kabacoff (2022), Einspruch
(2022), and Wickham et al. (2023) (freely
available at this link).
Specifically for I/O psychologists, we also suggest three books on human
resources analytics in R: Caughlin (2023) (freely
available at this
link), McNulty (2022) (freely available at this
link), and Starbuck (2023) (freely available at
this
link).
R.version
## _
## platform x86_64-w64-mingw32
## arch x86_64
## os mingw32
## crt ucrt
## system x86_64, mingw32
## status
## major 4
## minor 4.1
## year 2024
## month 06
## day 14
## svn rev 86737
## language R
## version.string R version 4.4.1 (2024-06-14 ucrt)
## nickname Race for Your Life
Note that any text preceded by the # symbol is a comment
that is not considered by R.
# this is a comment
Here, we remove all objects from the R global environment to ensure
that we start from scratch.
# removing all objets from the workspace
rm(list=ls())
The following R packages are used in this document (see References section):
# required packages
packages <- c("osfr","birk","plyr","psych","lavaan","lme4","sjPlot","ggplot2","gridExtra","tidyverse")
# run this line to install all missing packages
xfun::pkg_attach2(packages, message = FALSE); rm(list=ls())
Moreover, since we work with existing data available from the OSF
repository at https://doi.org/10.17605/OSF.IO/87A9P, we use the
osfr package to download the S5_processedData
folder including the datasets. Note that the folder is downloaded in the
current working directory used by R, which can be visualized by running
the getwd() command.
# download dataset from OSF repository
library(osfr)
repo <- # retrieving repository
osf_retrieve_node("https://doi.org/10.17605/OSF.IO/87A9P")
osf_download(osf_ls_files(repo)[1, ], # downloading datasets into the current working directory
conflicts="overwrite")
1. Data manipulation steps
1.1. Data reading
First, we read the ild dataset including time-varying
variables such as task demands and task control, and the preliminary
questionnaire prelqs dataset including time-invariant
variables such as participants’ age and gender. Both datasets were
recorded using the CSV format and can be read with the
read.csv() function. Note that we set
stringsAsFactors = TRUE so that character string columns
are considered as categorical variables.
# reading ILD dataset
ild <- read.csv("S5_processedData/ESM_processed.csv",
stringsAsFactors = TRUE)
# reading preliminary questionnaire
prelqs <- read.csv("S5_processedData/RETRO_processed.csv",
stringsAsFactors = TRUE)
What if the data collection platform exports a separate file for
each participant?
Click here to view additional code
In our case, we do not need to merge multiple data files because the
dataset has already been unified (see
full report). Yet, since some platforms export separate files
grouping data by participant, it is worth illustrating how these can be
merged into a single unified dataset. For doing this, we firstly split
the ild dataset into separate data files that we save based
on participant identifiers (i.e., participants ID are not
reported in a dataset column but each file is named with the
corresponding participant identifier). Then, we use the
list.files function to list the names of, and the paths to,
each data file. Second, we create an empty data.frame ild2
with zero row and the same number of column than the original
ild dataset. Finally, we use a for-loop to read each data
file, recreate the ID variable based on the file name, and
add the new data to the empty dataset ild2 using the
rbind function. We can see that the resulting dataset
corresponds to the original ild dataset.
# saving data separately by participant after creating the "data-split" folder
dir.create("data-split") # creating the "data-split" folder inside the working directory
for(id in levels(as.factor(ild$ID))){ # saving data within the "data-split" folder
write.csv(subset(ild[ild$ID==id,],select=-ID),paste0("data-split/",id,".csv"),
row.names=FALSE) }
# note: the code above is just to illustrate this preliminary step
# selecting the name of the folder storing the data files
data.path <- "data-split"
# listing the file names within the data.path folder
fileNames <- list.files(data.path,full.names=TRUE)
fileNames # showing file names
## [1] "data-split/S001.csv" "data-split/S002.csv" "data-split/S003.csv"
## [4] "data-split/S004.csv" "data-split/S005.csv" "data-split/S006.csv"
## [7] "data-split/S007.csv" "data-split/S008.csv" "data-split/S009.csv"
## [10] "data-split/S010.csv" "data-split/S011.csv" "data-split/S012.csv"
## [13] "data-split/S013.csv" "data-split/S014.csv" "data-split/S015.csv"
## [16] "data-split/S016.csv" "data-split/S017.csv" "data-split/S018.csv"
## [19] "data-split/S019.csv" "data-split/S020.csv" "data-split/S021.csv"
## [22] "data-split/S022.csv" "data-split/S023.csv" "data-split/S024.csv"
## [25] "data-split/S025.csv" "data-split/S026.csv" "data-split/S027.csv"
## [28] "data-split/S028.csv" "data-split/S029.csv" "data-split/S030.csv"
## [31] "data-split/S031.csv" "data-split/S032.csv" "data-split/S033.csv"
## [34] "data-split/S034.csv" "data-split/S035.csv" "data-split/S036.csv"
## [37] "data-split/S037.csv" "data-split/S038.csv" "data-split/S039.csv"
## [40] "data-split/S040.csv" "data-split/S041.csv" "data-split/S042.csv"
## [43] "data-split/S043.csv" "data-split/S044.csv" "data-split/S045.csv"
## [46] "data-split/S046.csv" "data-split/S047.csv" "data-split/S048.csv"
## [49] "data-split/S049.csv" "data-split/S050.csv" "data-split/S051.csv"
## [52] "data-split/S052.csv" "data-split/S053.csv" "data-split/S054.csv"
## [55] "data-split/S055.csv" "data-split/S056.csv" "data-split/S057.csv"
## [58] "data-split/S058.csv" "data-split/S059.csv" "data-split/S060.csv"
## [61] "data-split/S061.csv" "data-split/S062.csv" "data-split/S063.csv"
## [64] "data-split/S064.csv" "data-split/S065.csv" "data-split/S066.csv"
## [67] "data-split/S067.csv" "data-split/S068.csv" "data-split/S069.csv"
## [70] "data-split/S070.csv" "data-split/S071.csv" "data-split/S072.csv"
## [73] "data-split/S073.csv" "data-split/S074.csv" "data-split/S075.csv"
## [76] "data-split/S076.csv" "data-split/S077.csv" "data-split/S078.csv"
## [79] "data-split/S079.csv" "data-split/S080.csv" "data-split/S081.csv"
## [82] "data-split/S082.csv" "data-split/S083.csv" "data-split/S084.csv"
## [85] "data-split/S085.csv" "data-split/S086.csv" "data-split/S087.csv"
## [88] "data-split/S088.csv" "data-split/S089.csv" "data-split/S090.csv"
## [91] "data-split/S091.csv" "data-split/S092.csv" "data-split/S093.csv"
## [94] "data-split/S094.csv" "data-split/S095.csv" "data-split/S096.csv"
## [97] "data-split/S097.csv" "data-split/S098.csv" "data-split/S099.csv"
## [100] "data-split/S100.csv" "data-split/S101.csv" "data-split/S102.csv"
## [103] "data-split/S103.csv" "data-split/S104.csv" "data-split/S105.csv"
## [106] "data-split/S106.csv" "data-split/S107.csv" "data-split/S108.csv"
## [109] "data-split/S109.csv" "data-split/S110.csv" "data-split/S111.csv"
## [112] "data-split/S112.csv" "data-split/S113.csv" "data-split/S114.csv"
## [115] "data-split/S115.csv" "data-split/S116.csv" "data-split/S117.csv"
## [118] "data-split/S118.csv" "data-split/S119.csv" "data-split/S120.csv"
## [121] "data-split/S121.csv" "data-split/S122.csv" "data-split/S123.csv"
## [124] "data-split/S124.csv" "data-split/S125.csv" "data-split/S126.csv"
## [127] "data-split/S127.csv" "data-split/S128.csv" "data-split/S129.csv"
## [130] "data-split/S130.csv" "data-split/S131.csv" "data-split/S132.csv"
## [133] "data-split/S133.csv" "data-split/S134.csv" "data-split/S135.csv"
## [136] "data-split/S136.csv" "data-split/S137.csv" "data-split/S138.csv"
## [139] "data-split/S139.csv" "data-split/S140.csv" "data-split/S141.csv"
## [142] "data-split/S142.csv" "data-split/S143.csv" "data-split/S144.csv"
## [145] "data-split/S145.csv" "data-split/S146.csv" "data-split/S147.csv"
## [148] "data-split/S148.csv" "data-split/S149.csv" "data-split/S150.csv"
## [151] "data-split/S151.csv" "data-split/S152.csv" "data-split/S153.csv"
## [154] "data-split/S154.csv" "data-split/S155.csv" "data-split/S156.csv"
## [157] "data-split/S157.csv" "data-split/S158.csv" "data-split/S159.csv"
## [160] "data-split/S160.csv" "data-split/S161.csv" "data-split/S162.csv"
## [163] "data-split/S163.csv" "data-split/S164.csv" "data-split/S165.csv"
## [166] "data-split/S166.csv" "data-split/S167.csv" "data-split/S168.csv"
## [169] "data-split/S169.csv" "data-split/S170.csv" "data-split/S171.csv"
## [172] "data-split/S172.csv" "data-split/S173.csv" "data-split/S174.csv"
## [175] "data-split/S175.csv" "data-split/S176.csv" "data-split/S177.csv"
## [178] "data-split/S178.csv" "data-split/S179.csv" "data-split/S180.csv"
## [181] "data-split/S181.csv" "data-split/S182.csv" "data-split/S183.csv"
## [184] "data-split/S184.csv" "data-split/S185.csv" "data-split/S186.csv"
## [187] "data-split/S187.csv" "data-split/S188.csv" "data-split/S189.csv"
## [190] "data-split/S190.csv" "data-split/S191.csv" "data-split/S192.csv"
## [193] "data-split/S193.csv" "data-split/S194.csv" "data-split/S195.csv"
## [196] "data-split/S196.csv" "data-split/S197.csv" "data-split/S198.csv"
## [199] "data-split/S199.csv" "data-split/S200.csv" "data-split/S201.csv"
## [202] "data-split/S202.csv" "data-split/S203.csv" "data-split/S204.csv"
## [205] "data-split/S205.csv" "data-split/S206.csv" "data-split/S207.csv"
## [208] "data-split/S208.csv" "data-split/S209.csv" "data-split/S210.csv"
## [211] "data-split/S211.csv"
# creating empty data.frame ild2
ild2 <- data.frame(matrix(nrow=0,ncol=37))
# reading and merging data files into a unified dataset 'ild2'
for(fileName in fileNames){ # for each file included in the dat.path folder...
newFile <- read.csv(fileName) # reading file
newFile$ID <- gsub("data-split/","", # extracting participant ID from file name
gsub(".csv","",fileName))
# adding new data to the empty data.frame (the row names should be the same)
ild2 <- rbind(ild2,newFile) }
# showing the unified dataset
ild2[,c("ID",colnames(ild2)[1:(ncol(ild)-1)])]
# showing the original dataset
ild
Then, we identify and select the main data columns of interest by
using squared brackets [rownames, colnames] standing for
‘data subset’. Note that the names of the selected columns should be
written within quotes (e.g., "ID") and should be included
in the c() function, standing for ‘combine’. Of note, while
the RunTimestamp and SubmissionTimestamp
variables were named by the survey recording system, the remaining
variables were carefully named to identify items belonging to the same
scale (e.g., items starting with “d” were included in the Task Demand
Scale, whereas items starting with “c” were included in the Task Control
Scale). As highlighted in the main manuscript, strategically naming the
variables is critical to prevent mistakes in the following steps and
improve the effectiveness and transparency of the data analysis
scripts.
# selecting columns of interest from ILD dataset
ild <- ild[,c("ID", # participant identifier
"RunTimestamp","SubmissionTimestamp", # temporal coordinates
"d1","d2","d3","d4", # task demands items
"c1","c2","c3", # task control items
"v1","v2","v3")] # negative valence items
# selecting columns of interest from preliminary questionnaire dataset
prelqs <- prelqs[,c("ID", # participant identifier
"age","gender")] # time-invariant variables
Finally, we take a first look at both datasets and the included
number of participants and observations. We can see that both datasets
include a total of 211 participants, with the ild dataset
including a total of 2015 observations.
# ILD dataset
nrow(ild) # original number of observations
## [1] 2015
nlevels(ild$ID) # original number of participants
## [1] 211
head(ild) # showing first six rows of data
# preliminary questionnaire dataset
nrow(prelqs) # original number of observations and participants
## [1] 211
head(prelqs) # showing first six rows of data
1.2. Temporal
synchronization
As a second step, we synchronize and verify the correctness of the
temporal coordinates associated with each data point. In our case,
temporal coordinates are only available for the ild
dataset. We can verify their correctness by firstly converting them as
POSIXct (i.e., the variable class used by R to work with
dates and times), by splitting time and date
information, and by checking whether response times are consistent with
scheduled times. Note that the as.POSIXct function requires
specifying the date-time format of the inputted character strings using
the format argument. For instance, the date format
“%Y-%m-%d” stands for dates expressed as “year-month-day”,
reporting years with century (e.g., “2025”) and months and
days as decimal numbers (e.g., “01” for January, and “02” for the second
day of the month), whereas the time format “%H:%M:%S”
stands for times expressed as “hours:minutes:seconds” as decimal numbers
(for more details, run ?strptime in the console).
# response initiation and submission time as POSIXct
ild$RunTimestamp <- as.POSIXct(ild$RunTimestamp,
format = "%Y-%m-%d %H:%M:%S")
ild$SubmissionTimestamp <- as.POSIXct(ild$SubmissionTimestamp,
format = "%Y-%m-%d %H:%M:%S")
# response initiation date as Date without time
ild$date <- as.Date(substr(ild$RunTimestamp,1,10),
format="%Y-%m-%d")
# response initiation time as POSIXct without date
ild$time <- as.POSIXct(substr(ild$RunTimestamp,12,19),
format = "%H:%M:%S")
Here, we plot the histograms of the resulting date and
time variables to verify the frequency of responses
initiated inside and outside the study temporal frames. Note that with
objects of class POSIXct the function hist
(for plotting histograms) requires specifying the temporal intervals to
be plotted with the argument breaks (for more details, run
?hist.POSIXt in the console), which we set to
"months" and "hours" for response dates and
times, respectively. We can see that response initiation dates and times
are compatible with the data collection period (i.e., October 2018 -
October 2019) and with the scheduled ESM timing (i.e., between 9:15 AM
and 6:15 PM), respectively. A few cases (\(n\) = 22) are slightly outside the
scheduled time intervals, but these might be due to variability in
temporal synchronization across devices, so we keep them.
# plotting date and time
par(mfrow=c(2,1)) # this is to have 2 plots in the same panel
hist(ild$date,breaks="months") # plotting date frequencies month-by-month
hist(ild$time,breaks="hours") # plotting time frequencies hour-by-hour

# number of cases with time outside the scheduled intervals
nrow(ild[!is.na(ild$time) &
(ild$time<as.POSIXct("09:15:00", format = "%H:%M:%S") |
ild$time>as.POSIXct("18:30:00", format = "%H:%M:%S")),])
## [1] 22
Moreover, we use the recoded temporal coordinates to create the
variable day, indexing the day of participation from 1 to
3. This is done by using a for-loop that compares each row
i in the ild dataset with the previous row
i-1. Then, the if and else
operators are used to establish the value of the day
variables, such that it is increased by one unit every time that the
value of the date variable increases by one day within the
same participant, whereas it is reset to the value “1” every time that
the value of the variable ID is different than the value
reported in the previous row (i.e., day 1 for a different
participant).
# creating day (i.e., day of participation from 1 to 3)
ild$day <- 1 # initially set as 1
for(i in 2:nrow(ild)){ # FOR each row starting from the second one...
if(ild[i,"ID"] != ild[i-1,"ID"]){ # IF the ID value is different than the previous row...
ild[i,"day"] <- 1 # ...restart from day 1.
} else { # IF the ID value is the same of the previous row...
if(!is.na(ild[i,"date"]) & # AND both current and previous date are not missing...
!is.na(ild[i-1,"date"]) &
as.POSIXlt(ild[i,"date"])$wday != # AND the date value is different than the previous row...
as.POSIXlt(ild[i-1,"date"])$wday){
ild[i,"day"] <- ild[i-1,"day"] + 1 # ...add 1 day.
} else{ # IF same ID value but the date value is the same than the previous row...
ild[i,"day"] <- ild[i-1,"day"] # ...keep the same day than the previous row.
}}}
# sanity check: day can only take value 1, 2, or 3 (ok)
table(ild$day)
##
## 1 2 3
## 753 647 615
Note that the day variable created above is only used to
identify the observations associated with the same participant-by-day
cluster, but it cannot be used to operationalize temporal distances as
it does not imply equidistant intervals. Indeed, participants were
allowed to freely choose whether starting on Monday, Wednesday, or
Friday, implying that the distance between day 1 and day 2 can be equal
to 2 days for some participants (i.e., from Monday to Wednesday or from
Wednesday to Friday) and 3 days for some other participants (i.e., from
Friday to Monday). To get a variable that indexes the day of the week by
accounting for the actual temporal distance between days (i.e., implying
equidistant intervals), it is possible to use the
as.POSIXlt function by extracting the weekday with the
$wday syntax. This returns the weekday number from 0
(Sunday) to 6 (Saturday). In our case, it can only get values 1 =
Monday, 3 = Wednesday, or 5 = Friday.
data.frame(ID = ild$ID, # participant ID
RunTimestamp = ild$RunTimestamp, # original date-time variable
day = ild$day, # participant-by-day indicator created above
wday = as.POSIXlt(ild$RunTimestamp)$wday) # day of week
Finally, we use the scheduled timestamps to create the variable
beep, indexing the measurement occasion within each day,
from 1 to 7. To account for potential variability in device temporal
synchronization, 10 minutes are subtracted from each lower timestamp and
added to each upper timestamp, respectively.
# listing minimum, central, and maximum scheduled time for each time point
times <- list(c("09:15:00","09:30:00","10:15:00"), # beep 1
c("10:20:00","10:30:00","10:40:00"), # beep 2
c("11:50:00","12:00:00","12:10:00"), # beep 3
c("13:20:00","13:30:00","13:40:00"), # beep 4
c("14:50:00","15:00:00","15:10:00"), # beep 5
c("16:20:00","16:30:00","16:40:00"), # beep 6
c("17:50:00","18:00:00","18:10:00")) # beep 7
# creating beep (i.e., survey number within day from 1 to 7)
for(i in 1:length(times)){ # assign beep value depending on each couple of min-max
ild[!is.na(ild$time) &
ild$time > (as.POSIXct(times[[i]][1], format = "%H:%M:%S") - 10*60) &
ild$time < (as.POSIXct(times[[i]][3], format = "%H:%M:%S") + 10*60),"beep"] <- i }
# correcting beep when response time is outside the scheduled intervals
times <- c("09:30:00","10:30:00","12:00:00","13:30:00","15:00:00","16:30:00","18:00:00") # vector of central times
for(i in 1:nrow(ild)){ # when time is outside the scheduled intervals, the closest 'beep' value is assigned
if(is.na(ild[i,"beep"]) & !is.na(ild[i,"time"])){ require(birk)
ild[i,"beep"] <- which.closest(as.POSIXct(times, format = "%H:%M:%S"), ild[i,"time"]) }}
table(ild$beep) # sanity check: beep can only take value 1-7 (ok)
##
## 1 2 3 4 5 6 7
## 271 287 302 289 282 281 267
Here, we visualize the original RunTimestamp variable
along with the newly created day and beep
variables.
ild[,c("ID","RunTimestamp","day","beep")]
1.3. Data cleaning
Third, we inspect and filter cases of missing and inaccurate data. To
track the total number of excluded observations and participants, we
initially record the original sample size at both levels.
# original number of observations
n1 <- nrow(ild)
# original number of participants
n2 <- nlevels(ild$ID)
Even more wisely, we might save the original dataset(s) before
applying any data cleaning procedure, so that if any error occurs in the
process we can start from this ‘checkpoint’ rather than restarting from
the beginning.
# saving data before cleaning it
ild.original <- ild
prelqs.original <- prelqs
# # run these lines to restart from the raw data
# ild <- ild.original
# prelqs <- prelqs.original
1.3.1. Incomplete responses
Here, we inspect and filer the number of cases with missing values
for some or all variables (e.g., possibly due to lack of compliance or
technical issues with the mobile app). First, we remove any participant
that only responded to the preliminary questionnaire but did not respond
to any ESM questionnaire (36, 1.8%), and vice versa (9, 4.3%). Note that
the %in% operator is used to update each dataset by only
including the ID values that are also included in the other
dataset, and vice versa.
# removing participants with no response to the preliminary questionnaire
prelqs <- prelqs[!is.na(prelqs$age) & # only retaining rows with non-missing values to age...
!is.na(prelqs$gender),] # ... and gender
ild <- ild[ild$ID %in% as.character(prelqs$ID),] # updating ild dataset
# removing participants with no response to any ESM questionnaire
ild <- ild[!is.na(ild$RunTimestamp),] # only retaining rows with non-missing values to RunTimeSamp
prelqs <- prelqs[prelqs$ID %in% as.character(ild$ID),] # updating prelqs dataset
Then, we filter all responses to the first beep of each
day (n = 260, 13.6%), which only included negative valence but
not task demands or task control items.
# removing all responses to the first daily survey (not including task demands and task control)
N1 <- nrow(ild) # saving original sample size for comparison
ild <- ild[ild$beep!=1,] # removing responses to the first survey of each day
cat("Removed",N1-nrow(ild),"responses (",round(100*(N1-nrow(ild))/N1,1),"% )")
## Removed 260 responses ( 13.6 % )
Finally, we inspect and remove all cases with missing responses to
any items (list-wise deletion). This is done by applying the
na.omit function to the subset of the ild
dataset that only includes the columns considered for the following
steps, namely the participant identifier ID, the temporal
coordinates of the responses, and the three multi-item scales.
Specifically, items are selected with the paste0 function,
which pastes the letter identifying each scale (i.e., v for
negative valence, d for task demands, and c
for task control) with the item number (e.g.,
paste0("v",1:3) returns a vector with values “v1”, “v2”,
and “v3”).
# list-wise deletion: removing cases with missing responses to any core variable
N1 <- nrow(ild) # saving original sample size for comparison
ild <-
na.omit(ild[,c("ID", # participant identifier
"RunTimestamp","SubmissionTimestamp","day","beep", # temporal coordinates
paste0("v",1:3),paste0("d",1:4),paste0("c",1:3))]) # item scores
cat("Removed",N1-nrow(ild),"responses (",round(100*(N1-nrow(ild))/N1,1),"% )")
## Removed 71 responses ( 4.3 % )
1.3.2. Double responses
As a subsequent step, we inspect cases of double responses (i.e., two
or more responses with the same ID, day, and
beep values). Again, this is done with the
paste0 function, which creates a variable combining
participant, day, and beep identifiers so that we can identify and
remove any cases of duplicated value for this variable. We can see that
no duplicated cases are detected in our case.
# detecting double responses (i.e. same ID, day, and beep value)
nrow(ild[duplicated(paste0(ild$ID, ild$day, ild$beep)),]) # no double responses in the dataset
## [1] 0
# # run this line to remove double responses
# ild <- ild[!duplicated(paste0(ild$ID, ild$day, ild$beep)),]
1.3.3. Careless responses
Here, we inspect and filter cases of potentially careless responses
and respondents. Specifically, following Curran
(2016), we illustrate careless response detection by looking for
cases with excessively fast response time. Considering the repetitive
nature of ESM designs, we apply a more conservative criterion than that
proposed by Curran (2016) (i.e., less than 2 seconds
per item) and we remove all response taking 1.5 seconds per item. In our
case, each ESM questionnaire included 21 items (see Menghini et al., 2023), resulting in a total cut-off
time of 21 \(\times\) 1.5 seconds =
31.5 seconds. We can see that the time difference between
SubmissionTimestamp and RunTimestamp values is
lower than 31.5 seconds only in one case.
# detecting cases with total response time below 31.5 seconds
nrow(ild[difftime(ild$SubmissionTimestamp,ild$RunTimestamp,units="secs") < 31.5,])
## [1] 1
# removing cases with total response time below 31.5 seconds
ild <- ild[difftime(ild$SubmissionTimestamp,ild$RunTimestamp,units="secs") > 31.5,]
1.3.4. Compliance rate
Finally, we inspect the participants’ compliance rate and apply our
exclusion criterion by removing all participants with less than 2 valid
observations per day. First, we use a for-loop to compute the response
rate of each participant (i.e., percentage of submitted responses over
the 18 scheduled questionnaires for each participant) and, within that
loop, we compute the total number of submitted responses for each
participant-by-day couple, adding these variables to the
prelqs dataset. Second, we plot the created response rate
variables. Finally, we exclude participants with less than 2 responses
per day.
# computing overall and daily compliance rate
for(i in 1:nrow(prelqs)){ # No. responses over total number of scheduled data points (n = 18)
prelqs[i,"compRate"] <- 100*nrow(ild[ild$ID==as.character(prelqs[i,"ID"]),])/18
for(day in 1:3){ # computing number of nonmissing data points per each day
prelqs[i,paste0("n.day",day)] <- nrow(ild[ild$ID==as.character(prelqs[i,"ID"]) & ild$day==day,]) }}
# plotting original compliance
par(mfrow=c(1,4))
for(i in c("compRate","n.day1","n.day2","n.day3")){ hist(prelqs[,i],main=i) }

# excluding participants with less than 2 valid data points per day
N2 <- nrow(prelqs); N1 <- nrow(ild) # saving original sample sizes for comparison
prelqs <- prelqs[prelqs$n.day1 >= 2 & prelqs$n.day2 >= 2 & prelqs$n.day3 >= 2,] # excluding participants from prelqs
ild <- ild[ild$ID %in% as.character(prelqs$ID),]
cat("Removed",N2-nrow(prelqs),"participants (",round(100*(N2-nrow(prelqs))/N2,1),
"% ) and",N1-nrow(ild),"observations (",round(100*(N1-nrow(ild))/N1,1),"% )")
## Removed 45 participants ( 27.1 % ) and 202 observations ( 12.8 % )
# plotting updated compliance
par(mfrow=c(1,4))
for(i in c("compRate","n.day1","n.day2","n.day3")){ hist(prelqs[,i],main=i) }

1.3.5. Excluded data
Here, we compute the total number of excluded observations and
participants by comparing the original sample sizes with those obtained
after applying all data cleaning procedures.
# resetting ID levels
ild$ID <- as.factor(as.character(ild$ID))
prelqs$ID <- as.factor(as.character(prelqs$ID))
# total number and percentage of excluded participants
n2 - nlevels(ild$ID); 100*(n2 - length(table(ild$ID)))/n2
## [1] 90
## [1] 42.65403
# total number and percentage of excluded observations
n1 - nrow(ild); 100*(n1 - nrow(ild))/n1
## [1] 637
## [1] 31.6129
1.4. Data merging
Here, we merge the time-invariant data included in the wide-form
prelqs dataset (i.e., participants’ age and
gender) with the time-varying data included in the
long-form ild dataset. This is done with the
join() function from the plyr package based on
the shared variable ID, identifying all the data points
associated with the same participant.
# data merging
library(plyr) # opening plyr package to use the join() function
ild <- join(ild, # long-form dataset
prelqs[,c("ID","age","gender")], # selecting columns from the wide-form dataset
by = "ID") # setting the column shared by the two datasets
# showing some columns from the merged dataset
ild[,c("ID","age","gender","day","beep","v1")]
1.5. Data centering
Here, we center any time-varying variable (i.e., ESM item scores such
as v1) by computing the corresponding cluster-mean (e.g.,
v1_mean) and cluster-mean-centered variable (e.g.,
v1_cmc) (see see Hamaker & Grasman,
2015; Wang & Maxwell, 2015). Since in R the
same result can be achieved in multiple ways, some of which might be
more intuitive for some users but not for others, this step is
implemented in two different ways, namely using base R and
with the tidyverse syntax.
Base R
With base R, cluster means (named “variable_mean”) are
computed using the aggregate function, which allows to
compute the mean of one or more variables (here, the negative valence,
task demand, and task control item scores) based on a grouping variable
(here, the participant identifier variable ID). Then, we
add cluster means to the ild long-form dataset and we use a
for-loop for computing cluster-mean-centered scores (named
“variable_cmc”) by subtracting cluster-mean values from the original
variable values, for each time-varying variable.
# selecting variable names
VarNames <- c("v1","v2","v3","d1","d2","d3","d4","c1","c2","c3")
# computing cluster-mean values of time-varying variables
means <- aggregate(x = ild[,VarNames], # variables to be aggregated
by = list(ild$ID), # cluster variable (it should be a list)
FUN = mean) # aggregating function (mean)
colnames(means) <- c("ID", # renaming variables to avoid duplicated names below
paste0(VarNames,"_mean"))
# joining cluster means to the long-form dataset
ild <- plyr::join(ild,means,by="ID")
# computing cluster-mean-centered values
for(VarName in VarNames){ # for each time-varying variable
ild[,paste0(VarName,"_cmc")] <- # the cluster-mean-centered variable (_cmc)...
ild[,VarName] - # ...is equal to the original variable...
ild[,paste0(VarName,"_mean")] } # ...minus the cluster-mean variable (_mean).
# showing example variables
ild[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
Tidyverse
Here, we replicate the same operations in three alternative ways
based on the tidyverse syntax (see Wickham
et al., 2023). In option A, we use the pipe operator
%>% to concatenate operations, the group_by
function to group operations by participant ID, and the
mutate function to specify which operations should be
applied (i.e., computing cluster-mean and cluster-mean-centered values).
In option B, we directly use the mutate function to specify
both the operations to be applied and the grouping variable (specified
with the argument .by). Finally, option C is an extension
of option B where we use the across function to repeat the
operations specified in the .fns argument across all the
columns specified in the .cols argument of the
mutate function. In this way, it is possible to avoid
manually rewriting the same operations for each variable, as in option A
and B.
# loading tidyverse package collection
library(tidyverse)
# option A: mutate and group_by
ild_tidyverse_A <-
ild %>%
group_by(ID) %>% # grouping operations by cluster variable "ID"
mutate(c1_mean = mean(c1), # computing cluster-mean variables (only examples)
d1_mean = mean(d1),
c1_cmc = c1 - c1_mean, # computing cluster-mean-centered variable (only examples)
d1_cmc = d1 - d1_mean)
ild_tidyverse_A[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
# option B: mutate with ".by"
ild_tidyverse_B <-
mutate(ild,
c1_mean = mean(c1), # computing cluster-mean variables (only examples)
d1_mean = mean(d1),
c1_cmc = c1 - c1_mean, # computing cluster-mean-centered variable (only examples)
d1_cmc = d1 - d1_mean,
.by = ID) # grouping operations by cluster variable "ID"
ild_tidyverse_B[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
# option C: repeat option B over multiple columns using the "across" command
ild_tidyverse_C <-
mutate(ild,
across(
# selecting all the columns on which repeating the operations
.cols = c("v1","v2","v3","d1","d2","d3","d4","c1","c2","c3"),
.fns = list( # list of operations to be repeated
mean =~ mean(.x), # computing cluster-mean variable
cmc =~ .x - mean(.x) )), # computing cluster-mean-centered variable
.by = ID) # grouping operations by cluster variable "ID"
ild_tidyverse_C[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
1.6. Psychometrics
Here, we evaluate the psychometric properties of the considered ESM
variables.
1.6.1. Item scores
First, we visualize the distribution of, and the correlations
between, item scores. We can see that all item scores share the same
range (1-7) and that most scores are quite symmetrically distributed,
although with some skewed distributions (items c1,
c2, and c3). Better symmetry is shown by
cluster-mean and cluster-mean-centered values.
# selecting items to be evaluated
items <- c("v1","v2","v3","d1","d2","d3","d4","c1","c2","c3")
# plotting original item score distributions
par(mfrow=c(2,5))
for(item in items){ hist(ild[,item],main=item,xlab="",breaks=30) }

# plotting cluster-mean score distributions
par(mfrow=c(2,5))
for(item in items){ hist(ild[!duplicated(ild$ID),paste0(item,"_mean")],main=paste0(item,"_mean"),xlab="",breaks=30) }

# plotting cluster-mean-centered score distributions
par(mfrow=c(2,5))
for(item in items){ hist(ild[,paste0(item,"_cmc")],main=paste0(item,"_cmc"),xlab="",breaks=30) }

Here, we compute and visualize the level-specific zero-order
correlations among the considered items. Level-1 (within-individual) and
level-2 (between-individual) correlations are computed by correlating
cluster-mean-centered (n = 1378) and cluster-mean values
(n = 121), respectively. We can see that correlations are in
the expected directions, with stronger correlations at level 2 (shown
below the main diagonal) than at level 1 (shown above the main
diagonal), and among item scores belonging to the same scale than among
scores from different scales.
# computing level-1 correlations
cor1 <- round(cor(ild[,items]),2)
# computing level-2 correlations
cor2 <- round(cor(ild[!duplicated(ild$ID),paste0(items,"_mean")]),2)
# visualizing correlations
library(psych)
cor1[lower.tri(cor1)] <- cor2[lower.tri(cor2)] # merging the two matrices
corPlot(cor1) # plotting correlation matrix

1.6.2. Reliability
indices
Here, we compute reliability indices based on generalizability
theory, that is by fitting a random-intercept-only model to decompose
the variance in item scores based on participants, items, time, and
their interactions (see Shrout & Lane (2012); Cranford et al., 2006). This is done using the
multilevel.reliability() function from the
psych package.
# isolating focused items
items <- c("v1","v2","v3")
# creating variable 'time' (joining day and beep)
ild$time <- paste(ild$day, ild$beep)
# computing reliability indices for negative valence items
multilevel.reliability(x = ild, # long-form dataset
grp = "ID", # cluster variable (categorical)
Time = "time", # time variable (categorical)
items = items, # item names
lmer = TRUE, aov = FALSE # additional arguments to be included
)[c("RkF", "Rc")] # selecting the target coefficients
## $RkF
## [1] 0.982208
##
## $Rc
## [1] 0.711622
# reliability indices for task demands
multilevel.reliability(ild, grp="ID", Time="time", items=c("d1","d2","d3","d4"),lmer=TRUE, aov=FALSE)[c("RkF","Rc")]
## $RkF
## [1] 0.9873327
##
## $Rc
## [1] 0.8243137
# reliability indices for task control
multilevel.reliability(ild, grp="ID", Time="time", items=c("c1","c2","c3"),lmer=TRUE, aov=FALSE)[c("RkF","Rc")]
## $RkF
## [1] 0.9799259
##
## $Rc
## [1] 0.7392937
1.6.3. MCFA
Here, we provide some illustrative code exemplifying a way to conduct
a multilevel confirmatory factor analysis (MCFA) of the considered
items, based on Jack & Jorgensen (2017).
Specifically, we fit and compare a configural model
fit.conf (with the same factor structure across levels) and
a weak-invariance model fit.winv (with both the same
structure and equivalent factor loadings across levels). We can see that
the two models fit the data comparably, and we trust the weak-invariance
model fit.winv.
# model specification: configural model (same structure across levels)
m.conf <- 'level: 1
NegVal_w =~ v1 + v2 + v3
taskDem_w =~ d1 + d2 + d3 + d4
taskCon_w =~ c1 + c2 + c3
level: 2
NegVal_b =~ v1 + v2 + v3
taskDem_b =~ d1 + d2 + d3 + d4
taskCon_b =~ c1 + c2 + c3'
# model specification: weak-invariance model (same structure and loadings across levels)
m.winv <- 'level: 1
NegVal_w =~ a*v1 + b*v2 + c*v3
taskDem_w =~ d*d1 + e*d2 + f*d3 + g*d4
taskCon_w =~ h*c1 + i*c2 + j*c3
level: 2
NegVal_b =~ a*v1 + b*v2 + c*v3
taskDem_b =~ d*d1 + e*d2 + f*d3 + g*d4
taskCon_b =~ h*c1 + i*c2 + j*c3
'
# model fit (note: some participants show no variance in some items, which is quite common)
library(lavaan)
fit.conf <- cfa(model = m.conf, data = ild, cluster="ID", std.lv=TRUE)
fit.winv <- cfa(model = m.winv, data = ild, cluster="ID", std.lv=TRUE)
# fit indices
round(lavInspect(fit.conf, what = "fit")[c("rmsea","cfi","srmr_within","srmr_between")],3) # configural
## rmsea cfi srmr_within srmr_between
## 0.033 0.979 0.031 0.059
round(lavInspect(fit.winv, what = "fit")[c("rmsea","cfi","srmr_within","srmr_between")],3) # weak invariance
## rmsea cfi srmr_within srmr_between
## 0.033 0.977 0.033 0.066
The inspection of the standardized parameters estimated by the
weak-invariance model reveals significant factor loadings ranging from
0.57 to 0.99. The model also estimates significant correlations among
latent variables in the expected directions, with the only exception of
that between demands and control at level 2 (not significant). Overall,
these results support the validity of the measurement model hypothesized
for the considered items.
# factor loadings from the selected model (weak invariance)
p <- standardizedsolution(fit.winv) # standardized coefficients
p[p$op=="=~",] # selecting factor loadings
# correlations among latent factors
p[p$lhs%in%c("NegVal_w","taskDem_w","taskCon_w") & p$lhs != p$rhs & p$op=="~~",] # level 1
p[p$lhs%in%c("NegVal_b","taskDem_b","taskCon_b") & p$lhs != p$rhs & p$op=="~~",] # level 2
1.6.4. Level-specific
reliability
Finally, we use the MCFA model selected above to compute
level-specific McDonald’s \(\omega\)
coefficients for each scale (see Geldhof et
al. 2014). We can see that all \(\omega\) coefficients are satisfactory with
values higher than 0.70 and higher coefficients at level 2 than at level
1.
# omega within negative valence
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="v","est.std"][1:3] # selecting factor loadings at level 1
round( sum(sl)^2 / # omega = sum of squared loadings /
(sum(sl)^2 + sum(1 - sl^2)) ,2) # (sum of squared loadings + residual variances)
## [1] 0.73
# omega within - task demands
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="d","est.std"][1:4]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2)
## [1] 0.83
# omega within - task control
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="c","est.std"][1:3]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2)
## [1] 0.74
# omega between - negative valence
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="v","est.std"][4:6]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2)
## [1] 0.94
# omega between - task demands
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="d","est.std"][5:6]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2)
## [1] 0.95
# omega between - task control
sl <- p[p$op=="=~" & substr(p$rhs,1,1)=="c","est.std"][4:6]
round( sum(sl)^2 / (sum(sl)^2 + sum(1 - sl^2)) ,2)
## [1] 0.91
Of note, the same coefficients can be obtained more effectively
(i.e., without fitting MCFA models) by using the omegaSEM
function of the multilevelTools package.
# loading multilevelTools library
library(multilevelTools)
# Negative valence
omegaSEM(items=paste0("v",1:3), id ="ID", data=ild)$Results
# Task demand
omegaSEM(items=paste0("d",1:4), id ="ID", data=ild)$Results
# Task control
omegaSEM(items=paste0("c",1:3), id ="ID", data=ild)$Results
1.7. Composite scores
Here, we compute the composite scores for each scale by averaging the
corresponding item scores. Then we compute the cluster-mean and the
cluster-mean-centered versions of the composite scores using the same
procedures shown in Step 5. As done above, we show how to implement this
step by using both base R and, alternatively, the
tidyverse syntax.
Base R
With base R, we use the apply function to
compute the composite scores NV, TD, and
TC by computing the mean score by row. Then, we use the
same code shown in section 1.5 to compute the cluster-mean (named
NVb, TDb, and TCb) and
cluster-mean-centered scores (named NVw, TDw,
and TCw).
# computing composite scores
ild$NV <- apply(ild[,c("v1","v2","v3")],1,mean,na.rm=TRUE) # Negative Valence
ild$TD <- apply(ild[,c("d1","d2","d3","d4")],1,mean,na.rm=TRUE) # Task Demands
ild$TC <- apply(ild[,c("c1","c2","c3")],1,mean,na.rm=TRUE) # Task Control
# selecting variable names
VarNames <- c("NV","TD","TC")
# computing cluster-mean values of time-varying variables (see section 1.5)
means <- aggregate(x=ild[,VarNames],by=list(ild$ID),FUN=mean)
colnames(means) <- c("ID",paste0(VarNames,"b"))
ild <- plyr::join(ild,means,by="ID")
# computing cluster-mean-centered values (see section 1.5)
for(VarName in VarNames){
ild[,paste0(VarName,"w")] <- ild[,VarName] - ild[,paste0(VarName,"b")] }
# showing example variables
ild[,c("ID","day","beep","NV","NVb","NVw")]
Here, we visualize the distributions of the resulting composite
scores. We can see that composite scores are quite symmetrically
distributed, although with some positive skewness for negative valence.
Cluster-mean-centered score distributions are more symmetric than
cluster-mean distributions.
# visualizing composite score distributions
par(mfrow=c(1,3))
for(VarName in VarNames){
hist(ild[,VarName],main=VarName,xlab="",breaks=30) }

# visualizing cluster means of composite scores
for(VarName in paste0(VarNames,"b")){
hist(ild[!duplicated(ild$ID),VarName],main=VarName,xlab="",breaks=30) }

# visualizing cluster-mean-centered composite scores
for(VarName in paste0(VarNames,"w")){
hist(ild[,VarName],main=VarName,xlab="",breaks=30) }

Tidyverse
Here, we replicate the same operations in two alternative ways based
on the tidyverse syntax (see Wickham et al.,
2023). In option A, we use the pipe operator %>% to
concatenate operations, the group_by function to group
operations by participant ID, and the mutate
function to specify which operations should be applied (i.e., computing
composite scores and their cluster means and cluster-mean-centered
values). In option B, we directly use the mutate function
to specify all operations to be applied and the grouping variable
(specified with the argument .by).
# loading tidyverse package collection
library(tidyverse)
# option A: mutate and group_by
ild_tidyverse_A <-
ild %>%
group_by(ID) %>% # grouping operations by cluster variable "ID"
# computing composite scores
mutate(NV = mean(c(v1,v2,v3)),
TD = mean(c(d1,d2,d3,d4)),
TC = mean(c(c1,c2,c3)),
# computing cluster-mean variables
NV_mean = mean(NV),
TD_mean = mean(TD),
TC_mean = mean(TC),
# computing cluster-mean-centered variables
NV_cmc = NV - NV_mean,
TD_cmc = TD - TD_mean,
TC_cmc = TC - TC_mean)
ild_tidyverse_A[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
# option B: mutate with ".by"
ild_tidyverse_B <-
mutate(ild,
# computing composite scores
NV = mean(c(v1,v2,v3)),
TD = mean(c(d1,d2,d3,d4)),
TC = mean(c(c1,c2,c3)),
# computing cluster-mean variables
NV_mean = mean(NV),
TD_mean = mean(TD),
TC_mean = mean(TC),
# computing cluster-mean-centered variables
NV_cmc = NV - NV_mean,
TD_cmc = TD - TD_mean,
TC_cmc = TC - TC_mean,
.by = ID) # grouping operations by cluster variable "ID"
ild_tidyverse_B[,c("ID","day","beep","c1","c1_mean","c1_cmc","d1","d1_mean","d1_cmc")]
1.8. Lagging and
leading
Here, we provide some code exemplifying how to manipulate ILD data to
move a variable (task demands) one time point backward (lagging) or
forward (leading) , although such transformed variables are not used in
the following analyses. As done above, we show how to implement this
step by using both base R and, alternatively, the
tidyverse syntax.
Base R
With base R, lagging is implemented with a for-loop that
pastes the variable value from the previous row if the values of both
participant (i.e., ID) and time identifiers (i.e.,
day) are equal to those of the previous row. Similarly,
leading is implemented with a for-loop the pastes the variable value
from the following row if the participant and time values are equal to
those of the following row. Here, we show an example with the variable
TD.
# saving data as an alternative dataset
ild_baseR <- ild[,c("ID","day","TD")]
# lagging TD variable
for(i in 2:nrow(ild)){ # for each row in the ild dataset
if(ild[i,"ID"] == ild[i-1,"ID"] & # IF same ID of the previous row...
ild[i,"day"] == ild[i-1,"day"]){ # ...AND same day of the previous row...
ild_baseR[i,"TD.lag"] <- ild[i-1,"TD"] # ...paste the value of the previous row
}}
# leading TD variable
for(i in 1:(nrow(ild)-1)){ # for each row in the ild dataset
if(ild[i,"ID"] == ild[i+1,"ID"] & # IF same ID of the next row...
ild[i,"day"] == ild[i+1,"day"]){ # ...AND same day of the next row...
ild_baseR[i,"TD.lead"] <- ild[i+1,"TD"] # ...paste the value of the next row
}}
# showing original, lagged, and led variable
ild_baseR[,c("ID","day","TD","TD.lag","TD.lead")]
Tidyverse
Here, we replicate the same operations in three alternative ways
based on the tidyverse syntax (see Wickham
et al., 2023), all of which uses the lag and the
lead, functions within the mutate function. In
option A, In option A, we use the pipe operator %>% to
concatenate operations, the group_by function to group
operations by participant ID and day, and the
mutate, lag, and lead functions
to specify which operations should be applied (i.e., lagging and leading
by n = 1 within the same day and the participant). In option B,
we directly use the mutate function to specify both the
operations to be applied and the two grouping variables (specified with
the argument .by). Finally, option C is an extension of
option B where we use the across function to repeat the
operations specified in the .fns argument across all the
columns specified in the .cols argument of the
mutate function. In this way, it is possible to avoid
manually rewriting the same operations for each variable, as in option A
and B.
# loading tidyverse package collection
library(tidyverse)
# option A: mutate and group_by
ild_tidyverse_A <-
ild %>%
group_by(ID,day) %>% # grouping operations by cluster variable "ID"
mutate(TD.lag = lag(TD, n = 1), # lagging the TD variable
TD.lead = lead(TD, n = 1)) # leading the TD variableriable
ild_tidyverse_A[,c("ID","day","TD","TD.lag","TD.lead")] # showing data
# option B: mutate with ".by"
ild_tidyverse_B <-
mutate(ild,
TD.lag = lag(TD, n = 1), # lagging the TD variable
TD.lead = lead(TD, n = 1), # leading the TD variable
.by = c(ID,day)) # grouping operations by cluster variable "ID"
ild_tidyverse_B[,c("ID","day","TD","TD.lag","TD.lead")] # showing data
# option C: repeat option B over multiple columns using the "across" command
ild_tidyverse_C <-
mutate(ild,
across(
# selecting all the columns on which repeating the operations
.cols = c("TD","TC","NV"),
.fns = list( # list of operations to be repeated
lag =~ lag(.x, n = 1), # lagging the TD variable
lead =~ lead(.x, n = 1) )), # leading the TD variable
.by = c(ID,day)) # grouping operations by cluster variable "ID"
ild_tidyverse_C[,c("ID","day","TD","TD_lag","TD_lead","TC","TC_lag","TC_lead")] # showing data
2. Data analysis
2.1. Descriptive
statistics
Here, we compute descriptive statistics, namely the number of
included observations and participants, mean, SD, and frequencies of
each included variables, the ICC(1) of time-varying variables, and the
level-specific correlations among the included quantitative variables.
To illustrate how the same output can be obtained in multiple ways, we
compute descriptive statistics both using base R syntax
and, alternatively, using the psych package.
Base R
With base R, the mean and standard deviation of
quantitative variables and the frequency of categorical variables are
computed within a for-loop. A second for-loop is then used to extract
the variance components from intercept-only linear mixed-effects
regression models, which are used to estimate the ICC(1). Finally, we
use the cor function to compute and merge within- and
between-individual correlations.
# number of included observations
cat("Level 1:",nrow(ild),"observations; Level 2:",nrow(ild[!duplicated(ild$ID),]),"participants")
## Level 1: 1378 observations; Level 2: 121 participants
# selecting variable names
VarNames <- c("NV","TD","TC")
# computing mean and standard deviation
desc <- c() # empty vector to be filled with descriptive stats
for(VarName in VarNames){ # for each time-varying variable...
desc[VarName] <- # ...computing mean and SD and pasting them together
paste0(round(mean(ild[,VarName]),2),
" (",round(sd(ild[,VarName]),2),")") }
desc["age"] <- # same thing for age but based on the wide-form dataset
paste0(round(mean(prelqs$age),2),
" (",round(sd(prelqs$age),2),")")
desc["gender"] <- # frequency and % of categorical variables (gender)
paste0(table(prelqs$gender)[1]," F (",
round(100*prop.table(table(prelqs$gender)),2),"%)")
# computing ICC(1) based on variance decomposition
library(lme4) # loading package to fit linear mixed-effects regression models
icc <- c() # empty vector to be filled with ICC values
for(VarName in VarNames){ # foreach time-varying variable..
fit <- lmer(as.formula(paste(VarName,"~ (1|ID)")), data = ild) # fitting null multilevel model
tau00 <- summary(fit)$varcor$ID[[1]] # variance of the random intercept
sigma2 <- summary(fit)$sigma^2 # residual variance
icc <- c(icc, VarName = round(tau00/(tau00 + sigma2),2)) # ICC = tau00/(tau00+sigma2)
}
# computing level-specific correlations among time-varying variables
cor1 <- round(cor(ild[,paste0(VarNames,"w")]),2) # level 1 (cluster-mean-centered)
cor2 <- round(cor(ild[!duplicated(ild$ID),paste0(VarNames,"b")]),2) # level 2 (cluster means)
cor1[lower.tri(cor1)] <- cor2[lower.tri(cor2)] # merging the two matrices
rownames(cor1) <- colnames(cor1) <- VarNames # adding variable labels
# adding level-2 correlations with age + empty row for gender
cor1 <- rbind(cor1,
cor(x=ild[!duplicated(ild$ID),c(paste0(VarNames,"b"),"age")],)[4,1:3],
matrix(rep(NA,3),nrow=1))
rownames(cor1)[4:5] <- c("age","gender")
# joining and printing descriptive stats, ICC, and correlations
cbind(data.frame(Desc = desc, ICC = c(icc, NA, NA)), round(cor1, 2))
psych
Here, we illustrate how the same operations can be optimized with the
psych package. First, we use the describe
function to compute the number of observations, mean and standard
deviation of each quantitative variable. Second, we use the
statBy function to compute ICCs(1) for each time-varying
variable and level-specific correlations. Finally, we show how to
extract and report the significance level of each correlation
coefficient.
# loading psych package
library(psych)
# computing number of observations, mean and sd
desc <- rbind(describe(ild[,c("NV","TD","TC")])[,c("n","mean","sd")], # time-varying
describe(prelqs[,"age"])[,c("n","mean","sd")]) # time-invariant
# computing ICC(1)
icc <- c(round(statsBy(ild[,c("NV","TD","TC")],group=ild$ID)$ICC1[1:3],2))
# computing level-specific correlations
cors <- psych::statsBy(ild[,c("NV","TD","TC","age")],group=ild$ID)
cors$rwg[lower.tri(cors$rwg)] <- cors$rbg[lower.tri(cors$rbg)] # merging lv-1 & lv-2 correlations
# joining and printing descriptive stats, ICC, and correlations
desc <- cbind(data.frame(Desc = desc, ICC = c(icc, NA)), round(cors$rwg[,1:3], 2))
rownames(desc) <- c("NV","TD","TC","age") # renaming rows
colnames(desc) <- c("n","mean","SD","ICC","NV","TD","TC") # renaming columns
desc # printing descriptive stats
# optional: adding asterisks for p-values
cors$pwg[lower.tri(cors$pwg)] <- cors$pbg[lower.tri(cors$pbg)] # merging lv-1 & lv-2 p-values
p <- matrix(nrow=4,ncol=3) # creating empty matrix to be filled with significance levels
for(i in 1:4){
for(j in 1:3){
if(!is.na(cors$pwg[i,j]) & cors$pwg[i,j] != 1){
desc[i,j+4] <- paste0(desc[i,j+4], # adding asterisks to correlation coefficients
ifelse(cors$pwg[i,j] < .001,
"***",
ifelse(cors$pwg[i,j] < .01,
"**",
ifelse(cors$pwg[i,j] < .05,
"*","")))) }}}
desc # printing descriptive stats
2.2. Regression models
Here, we fit and print the two illustrative models testing JDC
hypotheses. This is done by including cluster-mean-centered task demands
TDw and task control TCw and their level-1
interaction in Model 1, whereas model 2 includes and tests the
cross-level interaction between cluster-mean-centered task demands
TDw and the cluster means of task control TCb.
In both models, we include age and gender as
level-2 covariates and a random slope for task demands. Both models are
fitted with the REML estimator (see McNeish,
2017).
# loading required packages
library(lme4); library(sjPlot)
# fitting models
fit1 <- lmer(NV ~ TDw * TCw + age + gender + (TDw|ID), data = ild)
fit2 <- lmer(NV ~ TDw * TCb + age + gender + (TDw|ID), data = ild)
# printing output table
tab_model(fit1, fit2,
show.se = TRUE, collapse.se = TRUE, p.val = "wald", # Wald approximation
show.ci = FALSE, show.icc = FALSE)
|
|
NV
|
NV
|
|
Predictors
|
Estimates
|
p
|
Estimates
|
p
|
|
(Intercept)
|
3.20 (0.29)
|
<0.001
|
4.80 (0.43)
|
<0.001
|
|
TDw
|
0.10 (0.03)
|
0.002
|
0.37 (0.13)
|
0.005
|
|
TCw
|
-0.15 (0.02)
|
<0.001
|
|
|
|
age
|
0.00 (0.01)
|
0.583
|
-0.00 (0.01)
|
0.665
|
|
gender [M]
|
-0.02 (0.15)
|
0.897
|
-0.06 (0.14)
|
0.663
|
|
TDw × TCw
|
-0.02 (0.02)
|
0.350
|
|
|
|
TCb
|
|
|
-0.32 (0.07)
|
<0.001
|
|
TDw × TCb
|
|
|
-0.06 (0.03)
|
0.046
|
|
Random Effects
|
|
σ2
|
0.59
|
0.61
|
|
τ00
|
0.59 ID
|
0.49 ID
|
|
τ11
|
0.04 ID.TDw
|
0.05 ID.TDw
|
|
ρ01
|
0.06 ID
|
-0.03 ID
|
|
N
|
121 ID
|
121 ID
|
|
Observations
|
1378
|
1378
|
|
Marginal R2 / Conditional R2
|
0.031 / 0.533
|
0.092 / 0.518
|
Note that the marginal and conditional \(R^2\) are estimates of the proportion of
negative valence variance explained by fixed effects only and by both
fixed and random effects, respectively.
Finally, we plot the estimated interactions.
# loading required packages
library(ggplot2); library(gridExtra)
# setting graphical parameters
sd_tc1 <- round(sd(ild$TCw),2) # computing TC standard dev. at level 1
mean_tc2 <- round(mean(means$TCb),2) # computing mean TC at level 2
sd_tc2 <- round(sd(means$TCb),2) # computing TC standard dev. at level 2
labs <- c("-1 SD","+1 SD") # setting legend labels
cols <- c("black","#666666") # setting colors
lins <- c("solid","dashed") # setting line types
# plotting
p <- grid.arrange(
# Model 1 (TCw +/- 1 SD)
plot_model(fit1,type="pred",terms=c("TDw",paste0("TCw [",-sd_tc1,",",sd_tc1,"]"))) +
scale_color_manual(labels=labs,values=cols) +
scale_linetype_manual(labels=labs,values=lins) +
scale_fill_manual(labels=labs,values=cols) + ggtitle("") +
xlab("Task demand (within)") + ylab("Negative valence") +
guides(color=guide_legend(title="Task Control\n(within)")),
# Model 2 (Mean TCb +/- 1 SD)
plot_model(fit2,type="pred",
terms=c("TDw",paste0("TCb [",mean_tc2-sd_tc1,",",mean_tc2+sd_tc1,"]"))) +
scale_color_manual(labels=labs,values=cols) +
scale_linetype_manual(labels=labs,values=lins) +
scale_fill_manual(labels=labs,values=cols) + ggtitle("") +
xlab("Task demand (within)") + ylab("Negative valence") +
guides(color=guide_legend(title="Task control\n(between)")), nrow=1)

# exporting figure
ggsave("fig2.png", plot = p, dpi = 300)
3. Multiverse approach
Here, we integrate the code provided for each step into a unified
function ild.manip to illustrate how results might change
based on data manipulation choices. Note that some of the function
arguments are set by default as required by our illustrative
example.
show ild.manip
#' @title Intensive longitudinal data manipulation
#' @param long = long-form dataset (data.frame)
#' @param wide = wide-form dataset (data.frame)
#' @param cluster = name of the cluster variable identifying participants (character)
#' @param long.respTime = name of the time variable in the long-form dataset (character)
#' @param respTime.format = time format used by the long.respTime variable (character) (see ?strptime)
#' @param scheduledTimes = list of three-element character vectors reporting the minimum, central, and maximum time for each scheduled measurement using the same time format set in the scheduledTimes.format argument
#' @param scheduledTimes.format = time format (without date) used in the scheduledTimes argument (character) (default "%H:%M:%S")
#' @param long.variables = list of variable names in the long-form dataset (i.e., for each variable, it should include a list element named with the variable name and including a vector of variable names reporting the name of each item; with single-item measures only the variable name should be specified, without any vector)
#' @param wide.variables = list of variable names in the wide-form dataset (see long.variables)
#' @param remove.first.beep = logical value determining whether the first measurement occasion within each day should be excluded (TRUE) or not (FALSE, default)
#' @param remove.first.day = logical value determining whether the first day of each participant should be excluded (TRUE) or not (FALSE, default)
#' @param listwise.del = logical value determining whether a list-wise deletion should be applied (TRUE) or not (FALSE, default)
#' @param compliance.cutoff = numeric value indexing the minimum number of observations or compliance rate cut-off used to exclude participants (NA by default, meaning that all participants are included)
#' @param compliance.type = character value determining whether the compliance.cutoff value is expressed as the minimum number of observations (compliance.type = "obs") or as the minimum compliance rate (compliance.type="perc")
#' @param max.nobs = integer indexing the maximum number of responses per participant (required when compliance.type="perc")
ild.manip <- function(long, wide, cluster = "ID", long.respTime = "RunTimestamp",
respTime.format = "%Y-%m-%d %H:%M:%S",
scheduledTimes = list(c("09:15:00","09:30:00","10:15:00"), # beep 1
c("10:20:00","10:30:00","10:40:00"), # beep 2
c("11:50:00","12:00:00","12:10:00"), # beep 3
c("13:20:00","13:30:00","13:40:00"), # beep 4
c("14:50:00","15:00:00","15:10:00"), # beep 5
c("16:20:00","16:30:00","16:40:00"), # beep 6
c("17:50:00","18:00:00","18:10:00")), # beep 7
scheduledTimes.format = "%H:%M:%S",
long.variables = list(NV = c("v1","v2","v3"),
TD = c("d1","d2","d3","d4"),
TC = c("c1","c2","c3")),
wide.variables = list("gender","age"),
remove.first.beep = FALSE, remove.first.day = FALSE,
listwise.del = FALSE, compliance.cutoff = NA,
compliance.type = c("obs","perc"), max.nobs = 18){
# renaming variables
colnames(long)[which(colnames(long)==cluster)] <- "ID" # cluster variable in the long dataset
colnames(wide)[which(colnames(wide)==cluster)] <- "ID" # cluster variable in the wide dataset
colnames(long)[which(colnames(long)==long.respTime)] <- "respTime" # time variable in the long dataset
# 1) data reading (removing unuseful columns).........................................................
#.....................................................................................................
long <- long[,which(colnames(long) %in% c("ID","respTime",as.character(unlist(long.variables))))]
wide <- wide[,which(colnames(wide) %in% c("ID",as.character(unlist(wide.variables))))]
# print info
cat("Data pre-processing...\n\n")
# 2) temporal synchronization..........................................................................
#......................................................................................................
long$time <- as.POSIXct(strftime(as.POSIXct(long$respTime, format="%Y-%m-%d %H:%M:%S"),
format="%H:%M:%S"),format="%H:%M:%S") # resp time
long$date <- as.Date(substr(long$respTime,1,10),format="%Y-%m-%d") # resp date without time
# creating 'day' variable base on response dates
long$day <- 1
for(i in 2:nrow(long)){ if(long[i,"ID"] != long[i-1,"ID"]){ long[i,"day"] <- 1 } else {
if(!is.na(long[i,"date"]) & !is.na(long[i-1,"date"]) &
as.POSIXlt(long[i,"date"])$wday != as.POSIXlt(long[i-1,"date"])$wday){
long[i,"day"] <- long[i-1,"day"] + 1 } else{ long[i,"day"] <- long[i-1,"day"] }}}
# creating 'beep' variable based on scheduled timestamps
if(!is.na(scheduledTimes[[1]][1])){ central.times <- c() # saving vector of central times
for(i in 1:length(scheduledTimes)){ # assign beep value depending on each couple of min-max
long[!is.na(long$time) &
long$time > (as.POSIXct(scheduledTimes[[i]][1],
format = scheduledTimes.format) - 10*60) &
long$time < (as.POSIXct(scheduledTimes[[i]][3],
format = scheduledTimes.format) + 10*60),"beep"] <- i
central.times <- c(central.times, scheduledTimes[[i]][2]) }
# when time is outside the scheduled interval, the closest 'beep' is assigned
for(i in 1:nrow(long)){ require(birk)
if(is.na(long[i,"beep"]) & !is.na(long[i,"time"])){
long[i,"beep"] <- which.closest(as.POSIXct(central.times, format = scheduledTimes.format),
long[i,"time"]) }}}
# 3) data cleaning.....................................................................................
#......................................................................................................
n1.long<-nrow(long) # save N.obs for comparison
n2.long<-length(table(long$ID))
n2.wide<-length(table(wide$ID))
n <- 1; for(i in 1:length(wide.variables)){ if(length(wide.variables[i]) > 1){ n <- n + 1 }}
# 3.1) removing missing resps from the wide-form dataset...............................................
if(n == 1){ wide <- na.omit(wide[,c("ID",unlist(wide.variables))])
} else { VarNames <- "ID"
for(i in 1:length(wide.variables)){ VarNames <- c(VarNames,names(wide.variables[i])) }
wide <- na.omit(wide[,VarNames]) }
long <- long[long$ID %in% as.character(wide$ID),] # removing cases that are not included in the wide dataset
long$ID <- as.factor(as.character(long$ID)) # resetting levels
cat("Data cleaning:\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
"participants not in the wide dataset")
# 3.2) removing cases with missing responses to the long-form dataset..................................
long <- long[!is.na(long$respTime),]
long$ID <- as.factor(as.character(long$ID)) # resetting levels
wide <- wide[wide$ID %in% levels(long$ID),] # removing cases that are not included in the long dataset
wide$ID <- as.factor(as.character(wide$ID)) # resetting levels
cat("\n-",n2.wide-nrow(wide),"participants not in the long dataset")
# 3.3) removing first observation within each day......................................................
n1.long<-nrow(long); n2.long<-nlevels(long$ID) # saving sample sizes for comparison
if(isTRUE(remove.first.beep)){
if(!is.na(scheduledTimes[[1]][1])){
long <- long[long$beep!=1,] # removing 1st 'beep' when scheduledTimes are specified
} else { LONG <- long[0,] # removing the first daily observation when scheduledTimes are NOT specified
long$IDday <- paste(long$ID,long$day) # creating identifier based on both ID and day
for(obs in levels(as.factor(long$IDday))){ LONG <- rbind(LONG,long[long$IDday == obs,][-1,]) }
long <- LONG }}
# 3.4) removing first day..............................................................................
if(isTRUE(remove.first.day)){ long <- long[long$day!=1,] }
long$ID <- as.factor(as.character(long$ID)) # resetting levels
if(isTRUE(remove.first.beep) | isTRUE(remove.first.day)){
cat("\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
"participants following the removal of the 1st",
ifelse(isTRUE(remove.first.beep) & isTRUE(remove.first.day),"day and the 1st daily survey",
ifelse(isTRUE(remove.first.beep),"daily survey","day"))) }
# 3.5) list-wise deletion..............................................................................
n1.long<-nrow(long); n2.long<-nlevels(long$ID) # saving sample sizes for comparison
if(isTRUE(listwise.del)){ long <- na.omit(long[,c("ID","respTime","day",as.character(unlist(long.variables)))])
long$ID <- as.factor(as.character(long$ID)) # resetting levels
cat("\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
"participants following list-wise deletion")}
# 3.5) excluding participants based on compliance rate.................................................
if(!is.na(compliance.cutoff)){ n1.long<-nrow(long); n2.long<-nlevels(ild$ID) # saving sample sizes
if(compliance.type=="obs"){ # compliance based on overall number of observations
for(day in min(as.integer(long$day)):max(as.integer(long$day))){
for(i in 1:nrow(wide)){ # computing no. obs per day and participant
wide[i,paste0("n.day",day)] <- nrow(long[long$ID==as.character(wide[i,"ID"]) & long$day==day,]) }
colnames(wide)[ncol(wide)] <- "nDay" # renaming column
wide <- wide[wide$nDay >= compliance.cutoff,] # removing participants
colnames(wide)[ncol(wide)] <- paste0("n.day",day) }
} else if(compliance.type=="perc"){ # compliance based on percentage of responses
for(i in 1:nrow(wide)){
wide[i,"compRate"] <- 100*nrow(long[long$ID==as.character(wide[i,"ID"]),])/max.nobs }
wide <- wide[wide$compRate >= compliance.cutoff,] }
long <- long[long$ID %in% as.character(wide$ID),] # removing the same participants from the long dataset
long$ID <- as.factor(as.character(long$ID)) # resetting levels
cat("\n-",n1.long-nrow(long),"obs,",n2.long-nlevels(long$ID),
"participants with",ifelse(compliance.type=="obs",paste("less than",compliance.cutoff,"obs per day"),
paste("compliance rate <",compliance.cutoff,"%"))) }
# 4) data merging........................................................................................
#........................................................................................................
require(plyr)
long <- join(long, wide, by = "ID")
# 5) computing composite scores..........................................................................
#........................................................................................................
n <- 1; for(i in 1:length(long.variables)){ if(length(long.variables[[i]]) > 1){ n <- n + 1 }}
if(n > 1){
for(i in 1:length(long.variables)){
long[,names(long.variables)[i]] <- apply(long[,long.variables[[i]]],1,mean,na.rm=TRUE) }}
# 6) data centering......................................................................................
#........................................................................................................
if(n > 1){
for(VarName in names(long.variables)){
colnames(long)[colnames(long)==VarName] <- "VarName" # changing variable name
clust.means <- aggregate(x = long$VarName, # cluster means
by = list(long$ID), FUN = mean, na.rm = TRUE)
colnames(clust.means) <- c("ID","VarNameb") # renaming variable
long <- join(long, clust.means, by="ID") # joining cluster mean to long-form dataset
long$VarNamew <- long$VarName - long$VarNameb # cluster mean centering
colnames(long) <- gsub("VarName",VarName,colnames(long)) }} # back to the original variable name
# print info
long$ID <- as.factor(as.character(long$ID))
cat("\n\nTotal number of retained observations =",nrow(long),"from",nlevels(long$ID),"participants")
# returning data
return(long) }
3.1. Multiverse of datasets
First, we apply the function to the raw datasets by considering
alternative data manipulation scenarios.
# reading raw datasets
long <- read.csv("S5_processedData/ESM_processed.csv", stringsAsFactors = TRUE) # ILD dataset
wide <- read.csv("S5_processedData/RETRO_processed.csv", stringsAsFactors = TRUE) # preliminary questionnaire
# scenario #1: same settings as above (a part from the single careless response, which is retained)
m1 <- ild.manip(long, wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 2, compliance.type = "obs")
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 202 obs, 0 participants with less than 2 obs per day
##
## Total number of retained observations = 1379 from 121 participants
# scenario #2: no data cleaning (i.e., retaining all available observations)
m2 <- ild.manip(long, wide)
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
##
## Total number of retained observations = 1912 from 166 participants
# scenario #3: removing first response regardless of response time
m3 <- ild.manip(long, wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 2, compliance.type = "obs",
scheduledTimes = NA)
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 471 obs, 4 participants following the removal of the 1st daily survey
## - 60 obs, 2 participants following list-wise deletion
## - 237 obs, 13 participants with less than 2 obs per day
##
## Total number of retained observations = 1144 from 108 participants
# scenario #4: removing first day
m4 <- ild.manip(long, wide,
remove.first.day = TRUE, listwise.del = TRUE,
compliance.cutoff = 2, compliance.type = "obs")
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 692 obs, 7 participants following the removal of the 1st day
## - 206 obs, 1 participants following list-wise deletion
## - 84 obs, -5 participants with less than 2 obs per day
##
## Total number of retained observations = 930 from 126 participants
# scenario #5: stricter compliance rate (3+ observations per day)
m5 <- ild.manip(long, wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 3, compliance.type = "obs")
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 568 obs, 39 participants with less than 3 obs per day
##
## Total number of retained observations = 1013 from 82 participants
# scenario #6: compliance rate > 30%
m6 <- ild.manip(long, wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 30, compliance.type = "perc")
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 105 obs, -13 participants with compliance rate < 30 %
##
## Total number of retained observations = 1476 from 134 participants
# scenario #7: compliance rate > 75%
m7 <- ild.manip(long, wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 75, compliance.type = "perc")
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 260 obs, 0 participants following the removal of the 1st daily survey
## - 71 obs, 0 participants following list-wise deletion
## - 1231 obs, 98 participants with compliance rate < 75 %
##
## Total number of retained observations = 350 from 23 participants
# scenario #8: (4) and (7)
m8 <- ild.manip(long, wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 30, compliance.type = "perc",
scheduledTimes = NA)
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 471 obs, 4 participants following the removal of the 1st daily survey
## - 60 obs, 2 participants following list-wise deletion
## - 113 obs, -3 participants with compliance rate < 30 %
##
## Total number of retained observations = 1268 from 124 participants
# scenario #9: (4) and (8)
m9 <- ild.manip(long,wide,
remove.first.beep = TRUE, listwise.del = TRUE,
compliance.cutoff = 75, compliance.type = "perc",
scheduledTimes = NA)
## Data pre-processing...
##
## Data cleaning:
## - 67 obs, 9 participants not in the wide dataset
## - 45 participants not in the long dataset
## - 471 obs, 4 participants following the removal of the 1st daily survey
## - 60 obs, 2 participants following list-wise deletion
## - 1165 obs, 107 participants with compliance rate < 75 %
##
## Total number of retained observations = 216 from 14 participants
3.2. Results
Here, we fit the same models fitted above on each generated dataset,
and we summarize the results by reporting the value TRUE
(i.e., significant) or FALSE (i.e., non-significant) for
each main and interactive effect of interest. We can see that the
results obtained above are quite robust across the considered scenarios.
Specifically, the most robust findings concern the negative level-1
effect of task control (significant across all scenarios) and the lack
of level-1 interaction (non-significant across all scenarios). The main
effect of task demands estimated by Model 1 is also quite robust, being
non-significant only in one case (i.e., removal of the first day).
Finally, the main and interactive effects estimated by Model 2 become
non-significant only when a compliance rate of 70% is applied, yet the
resulting datasets are very small (i.e., n1 ranging from 216 to
358, n2 ranging from 14 to 23). Overall, such robustness checks
support the generalizability of our findings.
# multiverse of datasets as a list
m <- list(m1,m2,m3,m4,m5,m6,m7,m8,m9)
# data.frame of results to be filled
out <- data.frame(matrix(nrow=0,ncol=8))
colnames(out) <- c("N1","N2","m1.TDw","m1.TCw","m1.int","m2.TDw","m2.TCb","m2.int")
# fitting models on each dataset
for(i in 1:length(m)){
fit1 <- lmer(NV ~ TDw * TCw + age + gender + (TDw|ID), data = m[[i]])
fit2 <- lmer(NV ~ TDw * TCb + age + gender + (TDw|ID), data = m[[i]])
out <- rbind(out, # extracting results (i.e., effects marked as TRUE if Coeff./SE > 1.96, FALSE otherwise)
data.frame(N1 = length(residuals(fit1)), N2 = as.integer(summary(fit1)$ngrps), # sample sizes
m1.TDw=abs(summary(fit1)$coefficients[2,3])>1.96, # model 1 main effects
m1.TCw=abs(summary(fit1)$coefficients[3,3])>1.96,
m1.int=abs(summary(fit1)$coefficients[6,3])>1.96, # model 1 interaction
m2.TDw=abs(summary(fit2)$coefficients[2,3])>1.96, # model 2 main effects
m2.TCb=abs(summary(fit2)$coefficients[3,3])>1.96,
m2.int=abs(summary(fit2)$coefficients[6,3])>1.96)) } # model 2 interaction
cbind(data=c("1. Original","2. All in","3. 1st resp out","4. 1st day out", # printing results
"5. 3+ obs/day","6. 30% compl","7. 70% compl","8. (4) & (7)","19. (4) & (8)"),out) # naming scenarios
LS0tDQp0aXRsZTogIk1hbmlwdWxhdGlvbiBvZiBpbnRlbnNpdmUgbG9uZ2l0dWRpbmFsIGRhdGEiDQphdXRob3I6ICJMdWNhIE1lbmdoaW5pLCBQaC5ELiwgRW5yaWNvIFBlcmluZWxsaSwgUGguRC4sIENyaXN0aWFuIEJhbGR1Y2NpLCBQaC5ELiINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCmJpYmxpb2dyYXBoeTogW3BhY2thZ2VzLmJpYl0NCm5vY2l0ZTogJ0AqJw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNA0KICAgIGNzczogc3R5bGVzLmNzcw0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgdGhlbWU6IHVuaXRlZA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCjxicj4NCg0KIyBBaW1zIGFuZCBjb250ZW50DQoNClRoZSBwcmVzZW50IGRvY3VtZW50IGluY2x1ZGVzIHRoZSBSIGNvZGUgdG8gYmUgdXNlZCBmb3IgaW1wbGVtZW50aW5nIHRoZSBkYXRhIHByZS1wcm9jZXNzaW5nIHN0ZXBzIHJlcXVpcmVkIG9yIHJlY29tbWVuZGVkIHRvIHByZXBhcmUgaW50ZW5zaXZlIGxvbmdpdHVkaW5hbCBkZXNpZ24gKElMRCkgZGF0YXNldHMgZm9yIGJlaW5nIGFuYWx5emVkIHdpdGggbXVsdGlsZXZlbCBhbmQgb3RoZXIgZGF0YSBhbmFseXNpcyB0ZWNobmlxdWVzLiBBZnRlciBhIGZldyBzZXR0aW5nIHByb2NlZHVyZXMsIHRoZSBkb2N1bWVudCBkZXBpY3RzIGVhY2ggc3RlcCBiYXNlZCBvbiBzaW1wbGUgYW5kIGNvbW1lbnRlZCBSIGNvZGUgcmFuZ2luZyBmcm9tIGRhdGEgcmVhZGluZyB0byBkYXRhIG1lcmdpbmcsIGNsZWFuaW5nLCBhbmQgY2VudGVyaW5nLCB1cCB0byBwc3ljaG9tZXRyaWMgYW5hbHlzZXMgYW5kIGNvbXB1dGF0aW9uIG9mIHRoZSBjb21wb3NpdGUgc2NvcmVzLiBUaGVuLCB0aGUgZG9jdW1lbnQgaW5jbHVkZSBhIGZldyBleGFtcGxlcyBvZiBkZXNjcmlwdGl2ZSBhbmQgaW5mZXJlbnRpYWwgbXVsdGlsZXZlbCBhbmFseXNlcyB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGludmVzdGlnYXRlIHRoZSBqb2IgZGVtYW5kLWNvbnRyb2wgaHlwb3RoZXNlcyAoW0thcmFzZWssIDE5NzldKCNyZWYpKSBmcm9tIHRoZSBwcmUtcHJvY2Vzc2VkIGRhdGFzZXQuIEZpbmFsbHksIHRoZSBkb2N1bWVudCBlbmRzIHdpdGggYW4gaWxsdXN0cmF0aW9uIG9mIGhvdyBhIG11bHRpdmVyc2UgZGF0YSBtYW5pcHVsYXRpb24gYXBwcm9hY2ggY2FuIGJlIGFwcGxpZWQgdG8gZXZhbHVhdGUgdGhlIHJvYnVzdG5lc3Mgb2YgdGhlIG9idGFpbmVkIGZpbmRpbmdzLg0KDQpUaGUgZG9jdW1lbnQgYW5kIHRoZSBpbmNsdWRlZCBjb2RlIGFyZSBiYXNlZCBvbiBSIDQuNC4xLCBhcyByZXR1cm5lZCBieSB0aGUgYFIudmVyc2lvbmAgY29tbWFuZCBiZWxvdy4gVG8gZ2V0IHN0YXJ0IHdpdGggUiwgd2UgcmVjb21tZW5kIFtLYWJhY29mZiAoMjAyMildKCNyZWYpLCBbRWluc3BydWNoICgyMDIyKV0oI3JlZiksIGFuZCBbV2lja2hhbSBldCBhbC4gKDIwMjMpXSgjcmVmKSAoZnJlZWx5IGF2YWlsYWJsZSBhdCBbdGhpcyBsaW5rXShodHRwczovL3I0ZHMuaGFkbGV5Lm56L2luZGV4Lmh0bWwpKS4gU3BlY2lmaWNhbGx5IGZvciBJL08gcHN5Y2hvbG9naXN0cywgd2UgYWxzbyBzdWdnZXN0IHRocmVlIGJvb2tzIG9uIGh1bWFuIHJlc291cmNlcyBhbmFseXRpY3MgaW4gUjogW0NhdWdobGluICgyMDIzKV0oI3JlZikgKGZyZWVseSBhdmFpbGFibGUgYXQgW3RoaXMgbGlua10oaHR0cHM6Ly9yZm9yaHIuY29tL2luZGV4Lmh0bWwjaHJhZ3Jvd3RoKSksIFtNY051bHR5ICgyMDIyKV0oI3JlZikgKGZyZWVseSBhdmFpbGFibGUgYXQgW3RoaXMgbGlua10oaHR0cHM6Ly9wZW9wbGVhbmFseXRpY3MtcmVncmVzc2lvbi1ib29rLm9yZy9pbmRleC5odG1sKSksIGFuZCBbU3RhcmJ1Y2sgKDIwMjMpXSgjcmVmKSAoZnJlZWx5IGF2YWlsYWJsZSBhdCBbdGhpcyBsaW5rXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2Jvb2svMTAuMTAwNy85NzgtMy0wMzEtMjg2NzQtMikpLg0KYGBge3IgIH0NClIudmVyc2lvbg0KYGBgDQoNCk5vdGUgdGhhdCBhbnkgdGV4dCBwcmVjZWRlZCBieSB0aGUgYCNgIHN5bWJvbCBpcyBhIGNvbW1lbnQgdGhhdCBpcyBub3QgY29uc2lkZXJlZCBieSBSLg0KYGBge3IgIH0NCiMgdGhpcyBpcyBhIGNvbW1lbnQNCmBgYA0KDQpIZXJlLCB3ZSByZW1vdmUgYWxsIG9iamVjdHMgZnJvbSB0aGUgUiBnbG9iYWwgZW52aXJvbm1lbnQgdG8gZW5zdXJlIHRoYXQgd2Ugc3RhcnQgZnJvbSBzY3JhdGNoLg0KYGBge3IgIH0NCiMgcmVtb3ZpbmcgYWxsIG9iamV0cyBmcm9tIHRoZSB3b3Jrc3BhY2UNCnJtKGxpc3Q9bHMoKSkNCmBgYA0KDQpUaGUgZm9sbG93aW5nIFIgcGFja2FnZXMgYXJlIHVzZWQgaW4gdGhpcyBkb2N1bWVudCAoc2VlIFtSZWZlcmVuY2VzXSgjcmVmKSBzZWN0aW9uKToNCmBgYHtyICB9DQojIHJlcXVpcmVkIHBhY2thZ2VzDQpwYWNrYWdlcyA8LSBjKCJvc2ZyIiwiYmlyayIsInBseXIiLCJwc3ljaCIsImxhdmFhbiIsImxtZTQiLCJzalBsb3QiLCJnZ3Bsb3QyIiwiZ3JpZEV4dHJhIiwidGlkeXZlcnNlIikNCmBgYA0KDQpgYGB7ciAgZWNobz1GQUxTRX0NCiMgdGhpcyBpcyBqdXN0IHRvIGdlbmVyYXRlIHBhY2thZ2VzIHJlZmVyZW5jZXMgYXQgdGhlIGVuZCBvZiB0aGUgZG9jdW1lbnQNCmtuaXRyOjp3cml0ZV9iaWIoYygucGFja2FnZXMoKSwgcGFja2FnZXMpLCJwYWNrYWdlcy5iaWIiKQ0KYGBgDQoNCmBgYHtyICBldmFsPUZBTFNFfQ0KIyBydW4gdGhpcyBsaW5lIHRvIGluc3RhbGwgYWxsIG1pc3NpbmcgcGFja2FnZXMNCnhmdW46OnBrZ19hdHRhY2gyKHBhY2thZ2VzLCBtZXNzYWdlID0gRkFMU0UpOyBybShsaXN0PWxzKCkpDQpgYGANCg0KTW9yZW92ZXIsIHNpbmNlIHdlIHdvcmsgd2l0aCBleGlzdGluZyBkYXRhIGF2YWlsYWJsZSBmcm9tIHRoZSBPU0YgcmVwb3NpdG9yeSBhdCA8aHR0cHM6Ly9kb2kub3JnLzEwLjE3NjA1L09TRi5JTy84N0E5UD4sIHdlIHVzZSB0aGUgYG9zZnJgIHBhY2thZ2UgdG8gZG93bmxvYWQgdGhlIGBTNV9wcm9jZXNzZWREYXRhYCBmb2xkZXIgaW5jbHVkaW5nIHRoZSBkYXRhc2V0cy4gTm90ZSB0aGF0IHRoZSBmb2xkZXIgaXMgZG93bmxvYWRlZCBpbiB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSB1c2VkIGJ5IFIsIHdoaWNoIGNhbiBiZSB2aXN1YWxpemVkIGJ5IHJ1bm5pbmcgdGhlIGBnZXR3ZCgpYCBjb21tYW5kLg0KYGBge3IgIGV2YWw9RkFMU0V9DQojIGRvd25sb2FkIGRhdGFzZXQgZnJvbSBPU0YgcmVwb3NpdG9yeQ0KbGlicmFyeShvc2ZyKQ0KcmVwbyA8LSAjIHJldHJpZXZpbmcgcmVwb3NpdG9yeQ0KICBvc2ZfcmV0cmlldmVfbm9kZSgiaHR0cHM6Ly9kb2kub3JnLzEwLjE3NjA1L09TRi5JTy84N0E5UCIpIA0Kb3NmX2Rvd25sb2FkKG9zZl9sc19maWxlcyhyZXBvKVsxLCBdLCAjIGRvd25sb2FkaW5nIGRhdGFzZXRzIGludG8gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkNCiAgICAgICAgICAgICBjb25mbGljdHM9Im92ZXJ3cml0ZSIpIA0KYGBgDQoNCjxicj4NCg0KIyAxLiBEYXRhIG1hbmlwdWxhdGlvbiBzdGVwcyB7I3N0ZXBzfQ0KDQojIyAxLjEuIERhdGEgcmVhZGluZw0KDQpGaXJzdCwgd2UgcmVhZCB0aGUgYGlsZGAgZGF0YXNldCBpbmNsdWRpbmcgdGltZS12YXJ5aW5nIHZhcmlhYmxlcyBzdWNoIGFzIHRhc2sgZGVtYW5kcyBhbmQgdGFzayBjb250cm9sLCBhbmQgdGhlIHByZWxpbWluYXJ5IHF1ZXN0aW9ubmFpcmUgYHByZWxxc2AgZGF0YXNldCBpbmNsdWRpbmcgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzIHN1Y2ggYXMgcGFydGljaXBhbnRzJyBhZ2UgYW5kIGdlbmRlci4gQm90aCBkYXRhc2V0cyB3ZXJlIHJlY29yZGVkIHVzaW5nIHRoZSBgQ1NWYCBmb3JtYXQgYW5kIGNhbiBiZSByZWFkIHdpdGggdGhlIGByZWFkLmNzdigpYCBmdW5jdGlvbi4gTm90ZSB0aGF0IHdlIHNldCBgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUVgIHNvIHRoYXQgY2hhcmFjdGVyIHN0cmluZyBjb2x1bW5zIGFyZSBjb25zaWRlcmVkIGFzIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4NCmBgYHtyICB9DQojIHJlYWRpbmcgSUxEIGRhdGFzZXQNCmlsZCA8LSByZWFkLmNzdigiUzVfcHJvY2Vzc2VkRGF0YS9FU01fcHJvY2Vzc2VkLmNzdiIsDQogICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpDQoNCiMgcmVhZGluZyBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlDQpwcmVscXMgPC0gcmVhZC5jc3YoIlM1X3Byb2Nlc3NlZERhdGEvUkVUUk9fcHJvY2Vzc2VkLmNzdiIsIA0KICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKSANCmBgYA0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCjxkZXRhaWxzPjxzdW1tYXJ5PipXaGF0IGlmIHRoZSBkYXRhIGNvbGxlY3Rpb24gcGxhdGZvcm0gZXhwb3J0cyBhIHNlcGFyYXRlIGZpbGUgZm9yIGVhY2ggcGFydGljaXBhbnQ/KiA8YnI+IENsaWNrIGhlcmUgdG8gdmlldyBhZGRpdGlvbmFsIGNvZGU8L3N1bW1hcnk+DQo8cD4NCg0KPGJyPg0KDQpJbiBvdXIgY2FzZSwgd2UgZG8gbm90IG5lZWQgdG8gbWVyZ2UgbXVsdGlwbGUgZGF0YSBmaWxlcyBiZWNhdXNlIHRoZSBkYXRhc2V0IGhhcyBhbHJlYWR5IGJlZW4gdW5pZmllZCAoW3NlZSBmdWxsIHJlcG9ydF0oaHR0cHM6Ly9sdWNhLW1lbmdoaW5pLmdpdGh1Yi5pby9FU01zY2FsZXMtd29ya3BsYWNlU3RyZXNzL1MyX2RhdGFQcm9jZXNzaW5nL1MyX2RhdGFQcm9jZXNzaW5nX3JlcG9ydC5odG1sKSkuIFlldCwgc2luY2Ugc29tZSBwbGF0Zm9ybXMgZXhwb3J0IHNlcGFyYXRlIGZpbGVzIGdyb3VwaW5nIGRhdGEgYnkgcGFydGljaXBhbnQsIGl0IGlzIHdvcnRoIGlsbHVzdHJhdGluZyBob3cgdGhlc2UgY2FuIGJlIG1lcmdlZCBpbnRvIGEgc2luZ2xlIHVuaWZpZWQgZGF0YXNldC4gRm9yIGRvaW5nIHRoaXMsIHdlIGZpcnN0bHkgc3BsaXQgdGhlIGBpbGRgIGRhdGFzZXQgaW50byBzZXBhcmF0ZSBkYXRhIGZpbGVzIHRoYXQgd2Ugc2F2ZSBiYXNlZCBvbiBwYXJ0aWNpcGFudCBpZGVudGlmaWVycyAoaS5lLiwgcGFydGljaXBhbnRzIGBJRGAgYXJlIG5vdCByZXBvcnRlZCBpbiBhIGRhdGFzZXQgY29sdW1uIGJ1dCBlYWNoIGZpbGUgaXMgbmFtZWQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBwYXJ0aWNpcGFudCBpZGVudGlmaWVyKS4gVGhlbiwgd2UgdXNlIHRoZSBgbGlzdC5maWxlc2AgZnVuY3Rpb24gdG8gbGlzdCB0aGUgbmFtZXMgb2YsIGFuZCB0aGUgcGF0aHMgdG8sIGVhY2ggZGF0YSBmaWxlLiBTZWNvbmQsIHdlIGNyZWF0ZSBhbiBlbXB0eSBkYXRhLmZyYW1lIGBpbGQyYCB3aXRoIHplcm8gcm93IGFuZCB0aGUgc2FtZSBudW1iZXIgb2YgY29sdW1uIHRoYW4gdGhlIG9yaWdpbmFsIGBpbGRgIGRhdGFzZXQuIEZpbmFsbHksIHdlIHVzZSBhIGZvci1sb29wIHRvIHJlYWQgZWFjaCBkYXRhIGZpbGUsIHJlY3JlYXRlIHRoZSBgSURgIHZhcmlhYmxlIGJhc2VkIG9uIHRoZSBmaWxlIG5hbWUsIGFuZCBhZGQgdGhlIG5ldyBkYXRhIHRvIHRoZSBlbXB0eSBkYXRhc2V0IGBpbGQyYCB1c2luZyB0aGUgYHJiaW5kYCBmdW5jdGlvbi4gV2UgY2FuIHNlZSB0aGF0IHRoZSByZXN1bHRpbmcgZGF0YXNldCBjb3JyZXNwb25kcyB0byB0aGUgb3JpZ2luYWwgYGlsZGAgZGF0YXNldC4NCmBgYHtyICBldmFsPUZBTFNFfQ0KIyBzYXZpbmcgZGF0YSBzZXBhcmF0ZWx5IGJ5IHBhcnRpY2lwYW50IGFmdGVyIGNyZWF0aW5nIHRoZSAiZGF0YS1zcGxpdCIgZm9sZGVyDQpkaXIuY3JlYXRlKCJkYXRhLXNwbGl0IikgIyBjcmVhdGluZyB0aGUgImRhdGEtc3BsaXQiIGZvbGRlciBpbnNpZGUgdGhlIHdvcmtpbmcgZGlyZWN0b3J5DQpmb3IoaWQgaW4gbGV2ZWxzKGFzLmZhY3RvcihpbGQkSUQpKSl7ICMgc2F2aW5nIGRhdGEgd2l0aGluIHRoZSAiZGF0YS1zcGxpdCIgZm9sZGVyDQogIHdyaXRlLmNzdihzdWJzZXQoaWxkW2lsZCRJRD09aWQsXSxzZWxlY3Q9LUlEKSxwYXN0ZTAoImRhdGEtc3BsaXQvIixpZCwiLmNzdiIpLA0KICAgICAgICAgICAgcm93Lm5hbWVzPUZBTFNFKSB9DQojIG5vdGU6IHRoZSBjb2RlIGFib3ZlIGlzIGp1c3QgdG8gaWxsdXN0cmF0ZSB0aGlzIHByZWxpbWluYXJ5IHN0ZXANCmBgYA0KYGBge3IgIH0NCiMgc2VsZWN0aW5nIHRoZSBuYW1lIG9mIHRoZSBmb2xkZXIgc3RvcmluZyB0aGUgZGF0YSBmaWxlcw0KZGF0YS5wYXRoIDwtICJkYXRhLXNwbGl0Ig0KDQojIGxpc3RpbmcgdGhlIGZpbGUgbmFtZXMgd2l0aGluIHRoZSBkYXRhLnBhdGggZm9sZGVyDQpmaWxlTmFtZXMgPC0gbGlzdC5maWxlcyhkYXRhLnBhdGgsZnVsbC5uYW1lcz1UUlVFKQ0KZmlsZU5hbWVzICMgc2hvd2luZyBmaWxlIG5hbWVzDQoNCiMgY3JlYXRpbmcgZW1wdHkgZGF0YS5mcmFtZSBpbGQyDQppbGQyIDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3c9MCxuY29sPTM3KSkNCg0KIyByZWFkaW5nIGFuZCBtZXJnaW5nIGRhdGEgZmlsZXMgaW50byBhIHVuaWZpZWQgZGF0YXNldCAnaWxkMicNCmZvcihmaWxlTmFtZSBpbiBmaWxlTmFtZXMpeyAjIGZvciBlYWNoIGZpbGUgaW5jbHVkZWQgaW4gdGhlIGRhdC5wYXRoIGZvbGRlci4uLg0KICBuZXdGaWxlIDwtIHJlYWQuY3N2KGZpbGVOYW1lKSAjIHJlYWRpbmcgZmlsZQ0KICBuZXdGaWxlJElEIDwtIGdzdWIoImRhdGEtc3BsaXQvIiwiIiwgIyBleHRyYWN0aW5nIHBhcnRpY2lwYW50IElEIGZyb20gZmlsZSBuYW1lDQogICAgICAgICAgICAgICAgICAgICBnc3ViKCIuY3N2IiwiIixmaWxlTmFtZSkpDQogICMgYWRkaW5nIG5ldyBkYXRhIHRvIHRoZSBlbXB0eSBkYXRhLmZyYW1lICh0aGUgcm93IG5hbWVzIHNob3VsZCBiZSB0aGUgc2FtZSkNCiAgaWxkMiA8LSByYmluZChpbGQyLG5ld0ZpbGUpIH0gDQoNCiMgc2hvd2luZyB0aGUgdW5pZmllZCBkYXRhc2V0DQppbGQyWyxjKCJJRCIsY29sbmFtZXMoaWxkMilbMToobmNvbChpbGQpLTEpXSldDQoNCiMgc2hvd2luZyB0aGUgb3JpZ2luYWwgZGF0YXNldA0KaWxkDQpgYGANCg0KPC9wPg0KPC9kZXRhaWxzPg0KPC9kaXY+DQoNClRoZW4sIHdlIGlkZW50aWZ5IGFuZCBzZWxlY3QgdGhlIG1haW4gZGF0YSBjb2x1bW5zIG9mIGludGVyZXN0IGJ5IHVzaW5nIHNxdWFyZWQgYnJhY2tldHMgYFtyb3duYW1lcywgY29sbmFtZXNdYCBzdGFuZGluZyBmb3IgJ2RhdGEgc3Vic2V0Jy4gTm90ZSB0aGF0IHRoZSBuYW1lcyBvZiB0aGUgc2VsZWN0ZWQgY29sdW1ucyBzaG91bGQgYmUgd3JpdHRlbiB3aXRoaW4gcXVvdGVzIChlLmcuLCBgIklEImApIGFuZCBzaG91bGQgYmUgaW5jbHVkZWQgaW4gdGhlIGBjKClgIGZ1bmN0aW9uLCBzdGFuZGluZyBmb3IgJ2NvbWJpbmUnLiBPZiBub3RlLCB3aGlsZSB0aGUgYFJ1blRpbWVzdGFtcGAgYW5kIGBTdWJtaXNzaW9uVGltZXN0YW1wYCB2YXJpYWJsZXMgd2VyZSBuYW1lZCBieSB0aGUgc3VydmV5IHJlY29yZGluZyBzeXN0ZW0sIHRoZSByZW1haW5pbmcgdmFyaWFibGVzIHdlcmUgY2FyZWZ1bGx5IG5hbWVkIHRvIGlkZW50aWZ5IGl0ZW1zIGJlbG9uZ2luZyB0byB0aGUgc2FtZSBzY2FsZSAoZS5nLiwgaXRlbXMgc3RhcnRpbmcgd2l0aCAiZCIgd2VyZSBpbmNsdWRlZCBpbiB0aGUgVGFzayBEZW1hbmQgU2NhbGUsIHdoZXJlYXMgaXRlbXMgc3RhcnRpbmcgd2l0aCAiYyIgd2VyZSBpbmNsdWRlZCBpbiB0aGUgVGFzayBDb250cm9sIFNjYWxlKS4gQXMgaGlnaGxpZ2h0ZWQgaW4gdGhlIG1haW4gbWFudXNjcmlwdCwgc3RyYXRlZ2ljYWxseSBuYW1pbmcgdGhlIHZhcmlhYmxlcyBpcyBjcml0aWNhbCB0byBwcmV2ZW50IG1pc3Rha2VzIGluIHRoZSBmb2xsb3dpbmcgc3RlcHMgYW5kIGltcHJvdmUgdGhlIGVmZmVjdGl2ZW5lc3MgYW5kIHRyYW5zcGFyZW5jeSBvZiB0aGUgZGF0YSBhbmFseXNpcyBzY3JpcHRzLg0KYGBge3IgIH0NCiMgc2VsZWN0aW5nIGNvbHVtbnMgb2YgaW50ZXJlc3QgZnJvbSBJTEQgZGF0YXNldA0KaWxkIDwtIGlsZFssYygiSUQiLCAjIHBhcnRpY2lwYW50IGlkZW50aWZpZXINCiAgICAgICAgICAgICAgIlJ1blRpbWVzdGFtcCIsIlN1Ym1pc3Npb25UaW1lc3RhbXAiLCAjIHRlbXBvcmFsIGNvb3JkaW5hdGVzDQogICAgICAgICAgICAgICJkMSIsImQyIiwiZDMiLCJkNCIsICMgdGFzayBkZW1hbmRzIGl0ZW1zDQogICAgICAgICAgICAgICJjMSIsImMyIiwiYzMiLCAjIHRhc2sgY29udHJvbCBpdGVtcw0KICAgICAgICAgICAgICAidjEiLCJ2MiIsInYzIildICMgbmVnYXRpdmUgdmFsZW5jZSBpdGVtcw0KDQojIHNlbGVjdGluZyBjb2x1bW5zIG9mIGludGVyZXN0IGZyb20gcHJlbGltaW5hcnkgcXVlc3Rpb25uYWlyZSBkYXRhc2V0DQpwcmVscXMgPC0gcHJlbHFzWyxjKCJJRCIsICMgcGFydGljaXBhbnQgaWRlbnRpZmllcg0KICAgICAgICAgICAgICAgICAgICAiYWdlIiwiZ2VuZGVyIildICMgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzDQpgYGANCg0KRmluYWxseSwgd2UgdGFrZSBhIGZpcnN0IGxvb2sgYXQgYm90aCBkYXRhc2V0cyBhbmQgdGhlIGluY2x1ZGVkIG51bWJlciBvZiBwYXJ0aWNpcGFudHMgYW5kIG9ic2VydmF0aW9ucy4gV2UgY2FuIHNlZSB0aGF0IGJvdGggZGF0YXNldHMgaW5jbHVkZSBhIHRvdGFsIG9mIGByIG5sZXZlbHMoaWxkJElEKWAgcGFydGljaXBhbnRzLCB3aXRoIHRoZSBgaWxkYCBkYXRhc2V0IGluY2x1ZGluZyBhIHRvdGFsIG9mIGByIG5yb3coaWxkKWAgb2JzZXJ2YXRpb25zLg0KYGBge3IgIH0NCiMgSUxEIGRhdGFzZXQNCm5yb3coaWxkKSAjIG9yaWdpbmFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCm5sZXZlbHMoaWxkJElEKSAjIG9yaWdpbmFsIG51bWJlciBvZiBwYXJ0aWNpcGFudHMNCmhlYWQoaWxkKSAjIHNob3dpbmcgZmlyc3Qgc2l4IHJvd3Mgb2YgZGF0YQ0KDQojIHByZWxpbWluYXJ5IHF1ZXN0aW9ubmFpcmUgZGF0YXNldA0KbnJvdyhwcmVscXMpICMgb3JpZ2luYWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhbmQgcGFydGljaXBhbnRzDQpoZWFkKHByZWxxcykgIyBzaG93aW5nIGZpcnN0IHNpeCByb3dzIG9mIGRhdGENCmBgYA0KDQo8YnI+DQoNCiMjIDEuMi4gVGVtcG9yYWwgc3luY2hyb25pemF0aW9uIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpBcyBhIHNlY29uZCBzdGVwLCB3ZSBzeW5jaHJvbml6ZSBhbmQgdmVyaWZ5IHRoZSBjb3JyZWN0bmVzcyBvZiB0aGUgdGVtcG9yYWwgY29vcmRpbmF0ZXMgYXNzb2NpYXRlZCB3aXRoIGVhY2ggZGF0YSBwb2ludC4gSW4gb3VyIGNhc2UsIHRlbXBvcmFsIGNvb3JkaW5hdGVzIGFyZSBvbmx5IGF2YWlsYWJsZSBmb3IgdGhlIGBpbGRgIGRhdGFzZXQuIFdlIGNhbiB2ZXJpZnkgdGhlaXIgY29ycmVjdG5lc3MgYnkgZmlyc3RseSBjb252ZXJ0aW5nIHRoZW0gYXMgYFBPU0lYY3RgIChpLmUuLCB0aGUgdmFyaWFibGUgY2xhc3MgdXNlZCBieSBSIHRvIHdvcmsgd2l0aCBkYXRlcyBhbmQgdGltZXMpLCBieSBzcGxpdHRpbmcgYHRpbWVgIGFuZCBgZGF0ZWAgaW5mb3JtYXRpb24sIGFuZCBieSBjaGVja2luZyB3aGV0aGVyIHJlc3BvbnNlIHRpbWVzIGFyZSBjb25zaXN0ZW50IHdpdGggc2NoZWR1bGVkIHRpbWVzLiBOb3RlIHRoYXQgdGhlIGBhcy5QT1NJWGN0YCBmdW5jdGlvbiByZXF1aXJlcyBzcGVjaWZ5aW5nIHRoZSBkYXRlLXRpbWUgZm9ybWF0IG9mIHRoZSBpbnB1dHRlZCBjaGFyYWN0ZXIgc3RyaW5ncyB1c2luZyB0aGUgYGZvcm1hdGAgYXJndW1lbnQuIEZvciBpbnN0YW5jZSwgdGhlIGRhdGUgZm9ybWF0ICJgJVktJW0tJWRgIiBzdGFuZHMgZm9yIGRhdGVzIGV4cHJlc3NlZCBhcyAieWVhci1tb250aC1kYXkiLCByZXBvcnRpbmcgeWVhcnMgd2l0aCBjZW50dXJ5IChlLmcuLCAiYDIwMjVgIikgYW5kIG1vbnRocyBhbmQgZGF5cyBhcyBkZWNpbWFsIG51bWJlcnMgKGUuZy4sICIwMSIgZm9yIEphbnVhcnksIGFuZCAiMDIiIGZvciB0aGUgc2Vjb25kIGRheSBvZiB0aGUgbW9udGgpLCB3aGVyZWFzIHRoZSB0aW1lIGZvcm1hdCAiYCVIOiVNOiVTYCIgc3RhbmRzIGZvciB0aW1lcyBleHByZXNzZWQgYXMgImhvdXJzOm1pbnV0ZXM6c2Vjb25kcyIgYXMgZGVjaW1hbCBudW1iZXJzIChmb3IgbW9yZSBkZXRhaWxzLCBydW4gYD9zdHJwdGltZWAgaW4gdGhlIGNvbnNvbGUpLg0KYGBge3IgIH0NCiMgcmVzcG9uc2UgaW5pdGlhdGlvbiBhbmQgc3VibWlzc2lvbiB0aW1lIGFzIFBPU0lYY3QNCmlsZCRSdW5UaW1lc3RhbXAgPC0gYXMuUE9TSVhjdChpbGQkUnVuVGltZXN0YW1wLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiKQ0KaWxkJFN1Ym1pc3Npb25UaW1lc3RhbXAgPC0gYXMuUE9TSVhjdChpbGQkU3VibWlzc2lvblRpbWVzdGFtcCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICIlWS0lbS0lZCAlSDolTTolUyIpDQoNCiMgcmVzcG9uc2UgaW5pdGlhdGlvbiBkYXRlIGFzIERhdGUgd2l0aG91dCB0aW1lDQppbGQkZGF0ZSA8LSBhcy5EYXRlKHN1YnN0cihpbGQkUnVuVGltZXN0YW1wLDEsMTApLA0KICAgICAgICAgICAgICAgICAgICBmb3JtYXQ9IiVZLSVtLSVkIikNCg0KIyByZXNwb25zZSBpbml0aWF0aW9uIHRpbWUgYXMgUE9TSVhjdCB3aXRob3V0IGRhdGUNCmlsZCR0aW1lIDwtIGFzLlBPU0lYY3Qoc3Vic3RyKGlsZCRSdW5UaW1lc3RhbXAsMTIsMTkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gIiVIOiVNOiVTIikNCmBgYA0KDQpIZXJlLCB3ZSBwbG90IHRoZSBoaXN0b2dyYW1zIG9mIHRoZSByZXN1bHRpbmcgYGRhdGVgIGFuZCBgdGltZWAgdmFyaWFibGVzIHRvIHZlcmlmeSB0aGUgZnJlcXVlbmN5IG9mIHJlc3BvbnNlcyBpbml0aWF0ZWQgaW5zaWRlIGFuZCBvdXRzaWRlIHRoZSBzdHVkeSB0ZW1wb3JhbCBmcmFtZXMuIE5vdGUgdGhhdCB3aXRoIG9iamVjdHMgb2YgY2xhc3MgYFBPU0lYY3RgIHRoZSBmdW5jdGlvbiBgaGlzdGAgKGZvciBwbG90dGluZyBoaXN0b2dyYW1zKSByZXF1aXJlcyBzcGVjaWZ5aW5nIHRoZSB0ZW1wb3JhbCBpbnRlcnZhbHMgdG8gYmUgcGxvdHRlZCB3aXRoIHRoZSBhcmd1bWVudCBgYnJlYWtzYCAoZm9yIG1vcmUgZGV0YWlscywgcnVuIGA/aGlzdC5QT1NJWHRgIGluIHRoZSBjb25zb2xlKSwgd2hpY2ggd2Ugc2V0IHRvIGAibW9udGhzImAgYW5kIGAiaG91cnMiYCBmb3IgcmVzcG9uc2UgZGF0ZXMgYW5kIHRpbWVzLCByZXNwZWN0aXZlbHkuIFdlIGNhbiBzZWUgdGhhdCByZXNwb25zZSBpbml0aWF0aW9uIGRhdGVzIGFuZCB0aW1lcyBhcmUgY29tcGF0aWJsZSB3aXRoIHRoZSBkYXRhIGNvbGxlY3Rpb24gcGVyaW9kIChpLmUuLCBPY3RvYmVyIDIwMTggLSBPY3RvYmVyIDIwMTkpIGFuZCB3aXRoIHRoZSBzY2hlZHVsZWQgRVNNIHRpbWluZyAoaS5lLiwgYmV0d2VlbiA5OjE1IEFNIGFuZCA2OjE1IFBNKSwgcmVzcGVjdGl2ZWx5LiBBIGZldyBjYXNlcyAoJG4kID0gMjIpIGFyZSBzbGlnaHRseSBvdXRzaWRlIHRoZSBzY2hlZHVsZWQgdGltZSBpbnRlcnZhbHMsIGJ1dCB0aGVzZSBtaWdodCBiZSBkdWUgdG8gdmFyaWFiaWxpdHkgaW4gdGVtcG9yYWwgc3luY2hyb25pemF0aW9uIGFjcm9zcyBkZXZpY2VzLCBzbyB3ZSBrZWVwIHRoZW0uDQpgYGB7ciAgfQ0KIyBwbG90dGluZyBkYXRlIGFuZCB0aW1lDQpwYXIobWZyb3c9YygyLDEpKSAjIHRoaXMgaXMgdG8gaGF2ZSAyIHBsb3RzIGluIHRoZSBzYW1lIHBhbmVsIA0KaGlzdChpbGQkZGF0ZSxicmVha3M9Im1vbnRocyIpICMgcGxvdHRpbmcgZGF0ZSBmcmVxdWVuY2llcyBtb250aC1ieS1tb250aA0KaGlzdChpbGQkdGltZSxicmVha3M9ImhvdXJzIikgIyBwbG90dGluZyB0aW1lIGZyZXF1ZW5jaWVzIGhvdXItYnktaG91cg0KDQojIG51bWJlciBvZiBjYXNlcyB3aXRoIHRpbWUgb3V0c2lkZSB0aGUgc2NoZWR1bGVkIGludGVydmFscw0KbnJvdyhpbGRbIWlzLm5hKGlsZCR0aW1lKSAmIA0KICAgICAgICAgICAoaWxkJHRpbWU8YXMuUE9TSVhjdCgiMDk6MTU6MDAiLCBmb3JtYXQgPSAiJUg6JU06JVMiKSB8IA0KICAgICAgICAgICAgICBpbGQkdGltZT5hcy5QT1NJWGN0KCIxODozMDowMCIsIGZvcm1hdCA9ICIlSDolTTolUyIpKSxdKQ0KYGBgDQoNCk1vcmVvdmVyLCB3ZSB1c2UgdGhlIHJlY29kZWQgdGVtcG9yYWwgY29vcmRpbmF0ZXMgdG8gY3JlYXRlIHRoZSB2YXJpYWJsZSBgZGF5YCwgaW5kZXhpbmcgdGhlIGRheSBvZiBwYXJ0aWNpcGF0aW9uIGZyb20gMSB0byAzLiBUaGlzIGlzIGRvbmUgYnkgdXNpbmcgYSBmb3ItbG9vcCB0aGF0IGNvbXBhcmVzIGVhY2ggcm93IGBpYCBpbiB0aGUgYGlsZGAgZGF0YXNldCB3aXRoIHRoZSBwcmV2aW91cyByb3cgYGktMWAuIFRoZW4sIHRoZSBgaWZgIGFuZCBgZWxzZWAgb3BlcmF0b3JzIGFyZSB1c2VkIHRvIGVzdGFibGlzaCB0aGUgdmFsdWUgb2YgdGhlIGBkYXlgIHZhcmlhYmxlcywgc3VjaCB0aGF0IGl0IGlzIGluY3JlYXNlZCBieSBvbmUgdW5pdCBldmVyeSB0aW1lIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBgZGF0ZWAgdmFyaWFibGUgaW5jcmVhc2VzIGJ5IG9uZSBkYXkgd2l0aGluIHRoZSBzYW1lIHBhcnRpY2lwYW50LCB3aGVyZWFzIGl0IGlzIHJlc2V0IHRvIHRoZSB2YWx1ZSAiMSIgZXZlcnkgdGltZSB0aGF0IHRoZSB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgYElEYCBpcyBkaWZmZXJlbnQgdGhhbiB0aGUgdmFsdWUgcmVwb3J0ZWQgaW4gdGhlIHByZXZpb3VzIHJvdyAoaS5lLiwgZGF5IDEgZm9yIGEgZGlmZmVyZW50IHBhcnRpY2lwYW50KS4NCmBgYHtyICB9DQojIGNyZWF0aW5nIGRheSAoaS5lLiwgZGF5IG9mIHBhcnRpY2lwYXRpb24gZnJvbSAxIHRvIDMpDQppbGQkZGF5IDwtIDEgIyBpbml0aWFsbHkgc2V0IGFzIDENCmZvcihpIGluIDI6bnJvdyhpbGQpKXsgIyBGT1IgZWFjaCByb3cgc3RhcnRpbmcgZnJvbSB0aGUgc2Vjb25kIG9uZS4uLg0KICBpZihpbGRbaSwiSUQiXSAhPSBpbGRbaS0xLCJJRCJdKXsgIyBJRiB0aGUgSUQgdmFsdWUgaXMgZGlmZmVyZW50IHRoYW4gdGhlIHByZXZpb3VzIHJvdy4uLg0KICAgIGlsZFtpLCJkYXkiXSA8LSAxICMgLi4ucmVzdGFydCBmcm9tIGRheSAxLg0KICAgIA0KICB9IGVsc2UgeyAgIyBJRiB0aGUgSUQgdmFsdWUgaXMgdGhlIHNhbWUgb2YgdGhlIHByZXZpb3VzIHJvdy4uLg0KICAgIGlmKCFpcy5uYShpbGRbaSwiZGF0ZSJdKSAmICMgQU5EIGJvdGggY3VycmVudCBhbmQgcHJldmlvdXMgZGF0ZSBhcmUgbm90IG1pc3NpbmcuLi4NCiAgICAgICAhaXMubmEoaWxkW2ktMSwiZGF0ZSJdKSAmIA0KICAgICAgIGFzLlBPU0lYbHQoaWxkW2ksImRhdGUiXSkkd2RheSAhPSAjIEFORCB0aGUgZGF0ZSB2YWx1ZSBpcyBkaWZmZXJlbnQgdGhhbiB0aGUgcHJldmlvdXMgcm93Li4uDQogICAgICAgICBhcy5QT1NJWGx0KGlsZFtpLTEsImRhdGUiXSkkd2RheSl7DQogICAgICBpbGRbaSwiZGF5Il0gPC0gaWxkW2ktMSwiZGF5Il0gKyAxICMgLi4uYWRkIDEgZGF5Lg0KICAgICAgDQogICAgfSBlbHNleyAjIElGIHNhbWUgSUQgdmFsdWUgYnV0IHRoZSBkYXRlIHZhbHVlIGlzIHRoZSBzYW1lIHRoYW4gdGhlIHByZXZpb3VzIHJvdy4uLg0KICAgICAgICBpbGRbaSwiZGF5Il0gPC0gaWxkW2ktMSwiZGF5Il0gIyAuLi5rZWVwIHRoZSBzYW1lIGRheSB0aGFuIHRoZSBwcmV2aW91cyByb3cuDQogICAgICAgIH19fQ0KDQojIHNhbml0eSBjaGVjazogZGF5IGNhbiBvbmx5IHRha2UgdmFsdWUgMSwgMiwgb3IgMyAob2spDQp0YWJsZShpbGQkZGF5KSANCmBgYA0KDQpOb3RlIHRoYXQgdGhlIGBkYXlgIHZhcmlhYmxlIGNyZWF0ZWQgYWJvdmUgaXMgb25seSB1c2VkIHRvIGlkZW50aWZ5IHRoZSBvYnNlcnZhdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzYW1lIHBhcnRpY2lwYW50LWJ5LWRheSBjbHVzdGVyLCBidXQgaXQgY2Fubm90IGJlIHVzZWQgdG8gb3BlcmF0aW9uYWxpemUgdGVtcG9yYWwgZGlzdGFuY2VzIGFzIGl0IGRvZXMgbm90IGltcGx5IGVxdWlkaXN0YW50IGludGVydmFscy4gSW5kZWVkLCBwYXJ0aWNpcGFudHMgd2VyZSBhbGxvd2VkIHRvIGZyZWVseSBjaG9vc2Ugd2hldGhlciBzdGFydGluZyBvbiBNb25kYXksIFdlZG5lc2RheSwgb3IgRnJpZGF5LCBpbXBseWluZyB0aGF0IHRoZSBkaXN0YW5jZSBiZXR3ZWVuIGRheSAxIGFuZCBkYXkgMiBjYW4gYmUgZXF1YWwgdG8gMiBkYXlzIGZvciBzb21lIHBhcnRpY2lwYW50cyAoaS5lLiwgZnJvbSBNb25kYXkgdG8gV2VkbmVzZGF5IG9yIGZyb20gV2VkbmVzZGF5IHRvIEZyaWRheSkgYW5kIDMgZGF5cyBmb3Igc29tZSBvdGhlciBwYXJ0aWNpcGFudHMgKGkuZS4sIGZyb20gRnJpZGF5IHRvIE1vbmRheSkuIFRvIGdldCBhIHZhcmlhYmxlIHRoYXQgaW5kZXhlcyB0aGUgZGF5IG9mIHRoZSB3ZWVrIGJ5IGFjY291bnRpbmcgZm9yIHRoZSBhY3R1YWwgdGVtcG9yYWwgZGlzdGFuY2UgYmV0d2VlbiBkYXlzIChpLmUuLCBpbXBseWluZyBlcXVpZGlzdGFudCBpbnRlcnZhbHMpLCBpdCBpcyBwb3NzaWJsZSB0byB1c2UgdGhlIGBhcy5QT1NJWGx0YCBmdW5jdGlvbiBieSBleHRyYWN0aW5nIHRoZSB3ZWVrZGF5IHdpdGggdGhlIGAkd2RheWAgc3ludGF4LiBUaGlzIHJldHVybnMgdGhlIHdlZWtkYXkgbnVtYmVyIGZyb20gMCAoU3VuZGF5KSB0byA2IChTYXR1cmRheSkuIEluIG91ciBjYXNlLCBpdCBjYW4gb25seSBnZXQgdmFsdWVzIDEgPSBNb25kYXksIDMgPSBXZWRuZXNkYXksIG9yIDUgPSBGcmlkYXkuDQpgYGB7ciB9DQpkYXRhLmZyYW1lKElEID0gaWxkJElELCAjIHBhcnRpY2lwYW50IElEDQogICAgICAgICAgIFJ1blRpbWVzdGFtcCA9IGlsZCRSdW5UaW1lc3RhbXAsICMgb3JpZ2luYWwgZGF0ZS10aW1lIHZhcmlhYmxlDQogICAgICAgICAgIGRheSA9IGlsZCRkYXksICMgcGFydGljaXBhbnQtYnktZGF5IGluZGljYXRvciBjcmVhdGVkIGFib3ZlDQogICAgICAgICAgIHdkYXkgPSBhcy5QT1NJWGx0KGlsZCRSdW5UaW1lc3RhbXApJHdkYXkpICMgZGF5IG9mIHdlZWsNCmBgYA0KDQpGaW5hbGx5LCB3ZSB1c2UgdGhlIHNjaGVkdWxlZCB0aW1lc3RhbXBzIHRvIGNyZWF0ZSB0aGUgdmFyaWFibGUgYGJlZXBgLCBpbmRleGluZyB0aGUgbWVhc3VyZW1lbnQgb2NjYXNpb24gd2l0aGluIGVhY2ggZGF5LCBmcm9tIDEgdG8gNy4gVG8gYWNjb3VudCBmb3IgcG90ZW50aWFsIHZhcmlhYmlsaXR5IGluIGRldmljZSB0ZW1wb3JhbCBzeW5jaHJvbml6YXRpb24sIDEwIG1pbnV0ZXMgYXJlIHN1YnRyYWN0ZWQgZnJvbSBlYWNoIGxvd2VyIHRpbWVzdGFtcCBhbmQgYWRkZWQgdG8gZWFjaCB1cHBlciB0aW1lc3RhbXAsIHJlc3BlY3RpdmVseS4NCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQojIGxpc3RpbmcgbWluaW11bSwgY2VudHJhbCwgYW5kIG1heGltdW0gc2NoZWR1bGVkIHRpbWUgZm9yIGVhY2ggdGltZSBwb2ludA0KdGltZXMgPC0gbGlzdChjKCIwOToxNTowMCIsIjA5OjMwOjAwIiwiMTA6MTU6MDAiKSwgIyBiZWVwIDENCiAgICAgICAgICAgICAgYygiMTA6MjA6MDAiLCIxMDozMDowMCIsIjEwOjQwOjAwIiksICMgYmVlcCAyDQogICAgICAgICAgICAgIGMoIjExOjUwOjAwIiwiMTI6MDA6MDAiLCIxMjoxMDowMCIpLCAjIGJlZXAgMw0KICAgICAgICAgICAgICBjKCIxMzoyMDowMCIsIjEzOjMwOjAwIiwiMTM6NDA6MDAiKSwgIyBiZWVwIDQNCiAgICAgICAgICAgICAgYygiMTQ6NTA6MDAiLCIxNTowMDowMCIsIjE1OjEwOjAwIiksICMgYmVlcCA1DQogICAgICAgICAgICAgIGMoIjE2OjIwOjAwIiwiMTY6MzA6MDAiLCIxNjo0MDowMCIpLCAjIGJlZXAgNg0KICAgICAgICAgICAgICBjKCIxNzo1MDowMCIsIjE4OjAwOjAwIiwiMTg6MTA6MDAiKSkgIyBiZWVwIDcNCg0KIyBjcmVhdGluZyBiZWVwIChpLmUuLCBzdXJ2ZXkgbnVtYmVyIHdpdGhpbiBkYXkgZnJvbSAxIHRvIDcpDQpmb3IoaSBpbiAxOmxlbmd0aCh0aW1lcykpeyAjIGFzc2lnbiBiZWVwIHZhbHVlIGRlcGVuZGluZyBvbiBlYWNoIGNvdXBsZSBvZiBtaW4tbWF4DQogIGlsZFshaXMubmEoaWxkJHRpbWUpICYgDQogICAgICAgIGlsZCR0aW1lID4gKGFzLlBPU0lYY3QodGltZXNbW2ldXVsxXSwgZm9ybWF0ID0gIiVIOiVNOiVTIikgLSAxMCo2MCkgJiANCiAgICAgICAgaWxkJHRpbWUgPCAoYXMuUE9TSVhjdCh0aW1lc1tbaV1dWzNdLCBmb3JtYXQgPSAiJUg6JU06JVMiKSArIDEwKjYwKSwiYmVlcCJdIDwtIGkgfQ0KDQojIGNvcnJlY3RpbmcgYmVlcCB3aGVuIHJlc3BvbnNlIHRpbWUgaXMgb3V0c2lkZSB0aGUgc2NoZWR1bGVkIGludGVydmFscw0KdGltZXMgPC0gYygiMDk6MzA6MDAiLCIxMDozMDowMCIsIjEyOjAwOjAwIiwiMTM6MzA6MDAiLCIxNTowMDowMCIsIjE2OjMwOjAwIiwiMTg6MDA6MDAiKSAjIHZlY3RvciBvZiBjZW50cmFsIHRpbWVzDQpmb3IoaSBpbiAxOm5yb3coaWxkKSl7ICMgd2hlbiB0aW1lIGlzIG91dHNpZGUgdGhlIHNjaGVkdWxlZCBpbnRlcnZhbHMsIHRoZSBjbG9zZXN0ICdiZWVwJyB2YWx1ZSBpcyBhc3NpZ25lZA0KICBpZihpcy5uYShpbGRbaSwiYmVlcCJdKSAmICFpcy5uYShpbGRbaSwidGltZSJdKSl7IHJlcXVpcmUoYmlyaykNCiAgICBpbGRbaSwiYmVlcCJdIDwtIHdoaWNoLmNsb3Nlc3QoYXMuUE9TSVhjdCh0aW1lcywgZm9ybWF0ID0gIiVIOiVNOiVTIiksIGlsZFtpLCJ0aW1lIl0pIH19DQp0YWJsZShpbGQkYmVlcCkgIyBzYW5pdHkgY2hlY2s6IGJlZXAgY2FuIG9ubHkgdGFrZSB2YWx1ZSAxLTcgKG9rKQ0KYGBgDQoNCkhlcmUsIHdlIHZpc3VhbGl6ZSB0aGUgb3JpZ2luYWwgYFJ1blRpbWVzdGFtcGAgdmFyaWFibGUgYWxvbmcgd2l0aCB0aGUgbmV3bHkgY3JlYXRlZCBgZGF5YCBhbmQgYGJlZXBgIHZhcmlhYmxlcy4NCmBgYHtyICB9DQppbGRbLGMoIklEIiwiUnVuVGltZXN0YW1wIiwiZGF5IiwiYmVlcCIpXQ0KYGBgDQoNCjxicj4NCg0KIyMgMS4zLiBEYXRhIGNsZWFuaW5nDQoNClRoaXJkLCB3ZSBpbnNwZWN0IGFuZCBmaWx0ZXIgY2FzZXMgb2YgbWlzc2luZyBhbmQgaW5hY2N1cmF0ZSBkYXRhLiBUbyB0cmFjayB0aGUgdG90YWwgbnVtYmVyIG9mIGV4Y2x1ZGVkIG9ic2VydmF0aW9ucyBhbmQgcGFydGljaXBhbnRzLCB3ZSBpbml0aWFsbHkgcmVjb3JkIHRoZSBvcmlnaW5hbCBzYW1wbGUgc2l6ZSBhdCBib3RoIGxldmVscy4NCmBgYHtyICB9DQojIG9yaWdpbmFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCm4xIDwtIG5yb3coaWxkKQ0KDQojIG9yaWdpbmFsIG51bWJlciBvZiBwYXJ0aWNpcGFudHMNCm4yIDwtIG5sZXZlbHMoaWxkJElEKQ0KYGBgDQoNCkV2ZW4gbW9yZSB3aXNlbHksIHdlIG1pZ2h0IHNhdmUgdGhlIG9yaWdpbmFsIGRhdGFzZXQocykgYmVmb3JlIGFwcGx5aW5nIGFueSBkYXRhIGNsZWFuaW5nIHByb2NlZHVyZSwgc28gdGhhdCBpZiBhbnkgZXJyb3Igb2NjdXJzIGluIHRoZSBwcm9jZXNzIHdlIGNhbiBzdGFydCBmcm9tIHRoaXMg4oCYY2hlY2twb2ludOKAmSByYXRoZXIgdGhhbiByZXN0YXJ0aW5nIGZyb20gdGhlIGJlZ2lubmluZy4gDQpgYGB7ciAgfQ0KIyBzYXZpbmcgZGF0YSBiZWZvcmUgY2xlYW5pbmcgaXQNCmlsZC5vcmlnaW5hbCA8LSBpbGQNCnByZWxxcy5vcmlnaW5hbCA8LSBwcmVscXMNCg0KIyAjIHJ1biB0aGVzZSBsaW5lcyB0byByZXN0YXJ0IGZyb20gdGhlIHJhdyBkYXRhDQojIGlsZCA8LSBpbGQub3JpZ2luYWwNCiMgcHJlbHFzIDwtIHByZWxxcy5vcmlnaW5hbA0KYGBgDQoNCjxicj4NCg0KIyMjIDEuMy4xLiBJbmNvbXBsZXRlIHJlc3BvbnNlcw0KDQpIZXJlLCB3ZSBpbnNwZWN0IGFuZCBmaWxlciB0aGUgbnVtYmVyIG9mIGNhc2VzIHdpdGggbWlzc2luZyB2YWx1ZXMgZm9yIHNvbWUgb3IgYWxsIHZhcmlhYmxlcyAoZS5nLiwgcG9zc2libHkgZHVlIHRvIGxhY2sgb2YgY29tcGxpYW5jZSBvciB0ZWNobmljYWwgaXNzdWVzIHdpdGggdGhlIG1vYmlsZSBhcHApLiBGaXJzdCwgd2UgcmVtb3ZlIGFueSBwYXJ0aWNpcGFudCB0aGF0IG9ubHkgcmVzcG9uZGVkIHRvIHRoZSBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlIGJ1dCBkaWQgbm90IHJlc3BvbmQgdG8gYW55IEVTTSBxdWVzdGlvbm5haXJlIChgciBucm93KGlsZFtpcy5uYShpbGQkUnVuVGltZXN0YW1wKSxdKWAsIGByIHJvdW5kKDEwMCpucm93KGlsZFtpcy5uYShpbGQkUnVuVGltZXN0YW1wKSxdKS9ucm93KGlsZCksMSlgJSksIGFuZCB2aWNlIHZlcnNhIChgciBucm93KHByZWxxc1tpcy5uYShwcmVscXMkYWdlKSB8IGlzLm5hKHByZWxxcyRnZW5kZXIpIHwgIXByZWxxcyRJRCVpbiVpbGQkSUQsXSlgLCBgciByb3VuZCgxMDAqbnJvdyhwcmVscXNbaXMubmEocHJlbHFzJGFnZSkgfCBpcy5uYShwcmVscXMkZ2VuZGVyKSB8ICFwcmVscXMkSUQlaW4laWxkJElELF0pL25yb3cocHJlbHFzKSwxKWAlKS4gTm90ZSB0aGF0IHRoZSBgJWluJWAgb3BlcmF0b3IgaXMgdXNlZCB0byB1cGRhdGUgZWFjaCBkYXRhc2V0IGJ5IG9ubHkgaW5jbHVkaW5nIHRoZSBgSURgIHZhbHVlcyB0aGF0IGFyZSBhbHNvIGluY2x1ZGVkIGluIHRoZSBvdGhlciBkYXRhc2V0LCBhbmQgdmljZSB2ZXJzYS4NCmBgYHtyICB9DQojIHJlbW92aW5nIHBhcnRpY2lwYW50cyB3aXRoIG5vIHJlc3BvbnNlIHRvIHRoZSBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlDQpwcmVscXMgPC0gcHJlbHFzWyFpcy5uYShwcmVscXMkYWdlKSAmICMgb25seSByZXRhaW5pbmcgcm93cyB3aXRoIG5vbi1taXNzaW5nIHZhbHVlcyB0byBhZ2UuLi4NCiAgICAgICAgICAgICAgICAgICAhaXMubmEocHJlbHFzJGdlbmRlciksXSAjIC4uLiBhbmQgZ2VuZGVyDQppbGQgPC0gaWxkW2lsZCRJRCAlaW4lIGFzLmNoYXJhY3RlcihwcmVscXMkSUQpLF0gIyB1cGRhdGluZyBpbGQgZGF0YXNldA0KDQojIHJlbW92aW5nIHBhcnRpY2lwYW50cyB3aXRoIG5vIHJlc3BvbnNlIHRvIGFueSBFU00gcXVlc3Rpb25uYWlyZQ0KaWxkIDwtIGlsZFshaXMubmEoaWxkJFJ1blRpbWVzdGFtcCksXSAjIG9ubHkgcmV0YWluaW5nIHJvd3Mgd2l0aCBub24tbWlzc2luZyB2YWx1ZXMgdG8gUnVuVGltZVNhbXANCnByZWxxcyA8LSBwcmVscXNbcHJlbHFzJElEICVpbiUgYXMuY2hhcmFjdGVyKGlsZCRJRCksXSAjIHVwZGF0aW5nIHByZWxxcyBkYXRhc2V0DQpgYGANCg0KVGhlbiwgd2UgZmlsdGVyIGFsbCByZXNwb25zZXMgdG8gdGhlIGZpcnN0IGBiZWVwYCBvZiBlYWNoIGRheSAoKm4qID0gYHIgbnJvdyhpbGRbIWlzLm5hKGlsZCRiZWVwKSAmIGlsZCRiZWVwPT0xLF0pYCwgYHIgcm91bmQoMTAwKm5yb3coaWxkWyFpcy5uYShpbGQkYmVlcCkgJiBpbGQkYmVlcD09MSxdKS9ucm93KGlsZFshaXMubmEoaWxkJGJlZXApLF0pLDEpYCUpLCB3aGljaCBvbmx5IGluY2x1ZGVkIG5lZ2F0aXZlIHZhbGVuY2UgYnV0IG5vdCB0YXNrIGRlbWFuZHMgb3IgdGFzayBjb250cm9sIGl0ZW1zLiANCmBgYHtyICB9DQojIHJlbW92aW5nIGFsbCByZXNwb25zZXMgdG8gdGhlIGZpcnN0IGRhaWx5IHN1cnZleSAobm90IGluY2x1ZGluZyB0YXNrIGRlbWFuZHMgYW5kIHRhc2sgY29udHJvbCkNCk4xIDwtIG5yb3coaWxkKSAjIHNhdmluZyBvcmlnaW5hbCBzYW1wbGUgc2l6ZSBmb3IgY29tcGFyaXNvbg0KaWxkIDwtIGlsZFtpbGQkYmVlcCE9MSxdICMgcmVtb3ZpbmcgcmVzcG9uc2VzIHRvIHRoZSBmaXJzdCBzdXJ2ZXkgb2YgZWFjaCBkYXkNCmNhdCgiUmVtb3ZlZCIsTjEtbnJvdyhpbGQpLCJyZXNwb25zZXMgKCIscm91bmQoMTAwKihOMS1ucm93KGlsZCkpL04xLDEpLCIlICkiKQ0KYGBgDQoNCkZpbmFsbHksIHdlIGluc3BlY3QgYW5kIHJlbW92ZSBhbGwgY2FzZXMgd2l0aCBtaXNzaW5nIHJlc3BvbnNlcyB0byBhbnkgaXRlbXMgKGxpc3Qtd2lzZSBkZWxldGlvbikuIFRoaXMgaXMgZG9uZSBieSBhcHBseWluZyB0aGUgYG5hLm9taXRgIGZ1bmN0aW9uIHRvIHRoZSBzdWJzZXQgb2YgdGhlIGBpbGRgIGRhdGFzZXQgdGhhdCBvbmx5IGluY2x1ZGVzIHRoZSBjb2x1bW5zIGNvbnNpZGVyZWQgZm9yIHRoZSBmb2xsb3dpbmcgc3RlcHMsIG5hbWVseSB0aGUgcGFydGljaXBhbnQgaWRlbnRpZmllciBgSURgLCB0aGUgdGVtcG9yYWwgY29vcmRpbmF0ZXMgb2YgdGhlIHJlc3BvbnNlcywgYW5kIHRoZSB0aHJlZSBtdWx0aS1pdGVtIHNjYWxlcy4gU3BlY2lmaWNhbGx5LCBpdGVtcyBhcmUgc2VsZWN0ZWQgd2l0aCB0aGUgYHBhc3RlMGAgZnVuY3Rpb24sIHdoaWNoIHBhc3RlcyB0aGUgbGV0dGVyIGlkZW50aWZ5aW5nIGVhY2ggc2NhbGUgKGkuZS4sIGB2YCBmb3IgbmVnYXRpdmUgdmFsZW5jZSwgYGRgIGZvciB0YXNrIGRlbWFuZHMsIGFuZCBgY2AgZm9yIHRhc2sgY29udHJvbCkgd2l0aCB0aGUgaXRlbSBudW1iZXIgKGUuZy4sIGBwYXN0ZTAoInYiLDE6MylgIHJldHVybnMgYSB2ZWN0b3Igd2l0aCB2YWx1ZXMgInYxIiwgInYyIiwgYW5kICJ2MyIpLg0KYGBge3IgIH0NCiMgbGlzdC13aXNlIGRlbGV0aW9uOiByZW1vdmluZyBjYXNlcyB3aXRoIG1pc3NpbmcgcmVzcG9uc2VzIHRvIGFueSBjb3JlIHZhcmlhYmxlDQpOMSA8LSBucm93KGlsZCkgIyBzYXZpbmcgb3JpZ2luYWwgc2FtcGxlIHNpemUgZm9yIGNvbXBhcmlzb24NCmlsZCA8LSANCiAgbmEub21pdChpbGRbLGMoIklEIiwgIyBwYXJ0aWNpcGFudCBpZGVudGlmaWVyDQogICAgICAgICAgICAgICAgICJSdW5UaW1lc3RhbXAiLCJTdWJtaXNzaW9uVGltZXN0YW1wIiwiZGF5IiwiYmVlcCIsICMgdGVtcG9yYWwgY29vcmRpbmF0ZXMNCiAgICAgICAgICAgICAgICAgcGFzdGUwKCJ2IiwxOjMpLHBhc3RlMCgiZCIsMTo0KSxwYXN0ZTAoImMiLDE6MykpXSkgIyBpdGVtIHNjb3Jlcw0KY2F0KCJSZW1vdmVkIixOMS1ucm93KGlsZCksInJlc3BvbnNlcyAoIixyb3VuZCgxMDAqKE4xLW5yb3coaWxkKSkvTjEsMSksIiUgKSIpDQpgYGANCg0KPGJyPg0KDQojIyMgMS4zLjIuIERvdWJsZSByZXNwb25zZXMNCg0KQXMgYSBzdWJzZXF1ZW50IHN0ZXAsIHdlIGluc3BlY3QgY2FzZXMgb2YgZG91YmxlIHJlc3BvbnNlcyAoaS5lLiwgdHdvIG9yIG1vcmUgcmVzcG9uc2VzIHdpdGggdGhlIHNhbWUgYElEYCwgYGRheWAsIGFuZCBgYmVlcGAgdmFsdWVzKS4gQWdhaW4sIHRoaXMgaXMgZG9uZSB3aXRoIHRoZSBgcGFzdGUwYCBmdW5jdGlvbiwgd2hpY2ggY3JlYXRlcyBhIHZhcmlhYmxlIGNvbWJpbmluZyBwYXJ0aWNpcGFudCwgZGF5LCBhbmQgYmVlcCBpZGVudGlmaWVycyBzbyB0aGF0IHdlIGNhbiBpZGVudGlmeSBhbmQgcmVtb3ZlIGFueSBjYXNlcyBvZiBkdXBsaWNhdGVkIHZhbHVlIGZvciB0aGlzIHZhcmlhYmxlLiBXZSBjYW4gc2VlIHRoYXQgbm8gZHVwbGljYXRlZCBjYXNlcyBhcmUgZGV0ZWN0ZWQgaW4gb3VyIGNhc2UuDQpgYGB7ciAgfQ0KIyBkZXRlY3RpbmcgZG91YmxlIHJlc3BvbnNlcyAoaS5lLiBzYW1lIElELCBkYXksIGFuZCBiZWVwIHZhbHVlKQ0KbnJvdyhpbGRbZHVwbGljYXRlZChwYXN0ZTAoaWxkJElELCBpbGQkZGF5LCBpbGQkYmVlcCkpLF0pICMgbm8gZG91YmxlIHJlc3BvbnNlcyBpbiB0aGUgZGF0YXNldA0KDQojICMgcnVuIHRoaXMgbGluZSB0byByZW1vdmUgZG91YmxlIHJlc3BvbnNlcw0KIyBpbGQgPC0gaWxkWyFkdXBsaWNhdGVkKHBhc3RlMChpbGQkSUQsIGlsZCRkYXksIGlsZCRiZWVwKSksXQ0KYGBgDQoNCjxicj4NCg0KIyMjIDEuMy4zLiBDYXJlbGVzcyByZXNwb25zZXMNCg0KSGVyZSwgd2UgaW5zcGVjdCBhbmQgZmlsdGVyIGNhc2VzIG9mIHBvdGVudGlhbGx5IGNhcmVsZXNzIHJlc3BvbnNlcyBhbmQgcmVzcG9uZGVudHMuIFNwZWNpZmljYWxseSwgZm9sbG93aW5nIFtDdXJyYW4gKDIwMTYpXSgjcmVmKSwgd2UgaWxsdXN0cmF0ZSBjYXJlbGVzcyByZXNwb25zZSBkZXRlY3Rpb24gYnkgbG9va2luZyBmb3IgY2FzZXMgd2l0aCBleGNlc3NpdmVseSBmYXN0IHJlc3BvbnNlIHRpbWUuIENvbnNpZGVyaW5nIHRoZSByZXBldGl0aXZlIG5hdHVyZSBvZiBFU00gZGVzaWducywgd2UgYXBwbHkgYSBtb3JlIGNvbnNlcnZhdGl2ZSBjcml0ZXJpb24gdGhhbiB0aGF0IHByb3Bvc2VkIGJ5IFtDdXJyYW4gKDIwMTYpXSgjcmVmKSAoaS5lLiwgbGVzcyB0aGFuIDIgc2Vjb25kcyBwZXIgaXRlbSkgYW5kIHdlIHJlbW92ZSBhbGwgcmVzcG9uc2UgdGFraW5nIDEuNSBzZWNvbmRzIHBlciBpdGVtLiBJbiBvdXIgY2FzZSwgZWFjaCBFU00gcXVlc3Rpb25uYWlyZSBpbmNsdWRlZCAyMSBpdGVtcyAoc2VlIFtNZW5naGluaSBldCBhbC4sIDIwMjNdKCNyZWYpKSwgcmVzdWx0aW5nIGluIGEgdG90YWwgY3V0LW9mZiB0aW1lIG9mIDIxICRcdGltZXMkIDEuNSBzZWNvbmRzID0gMzEuNSBzZWNvbmRzLiBXZSBjYW4gc2VlIHRoYXQgdGhlIHRpbWUgZGlmZmVyZW5jZSBiZXR3ZWVuIGBTdWJtaXNzaW9uVGltZXN0YW1wYCBhbmQgYFJ1blRpbWVzdGFtcGAgdmFsdWVzIGlzIGxvd2VyIHRoYW4gMzEuNSBzZWNvbmRzIG9ubHkgaW4gb25lIGNhc2UuDQpgYGB7ciAgfQ0KIyBkZXRlY3RpbmcgY2FzZXMgd2l0aCB0b3RhbCByZXNwb25zZSB0aW1lIGJlbG93IDMxLjUgc2Vjb25kcw0KbnJvdyhpbGRbZGlmZnRpbWUoaWxkJFN1Ym1pc3Npb25UaW1lc3RhbXAsaWxkJFJ1blRpbWVzdGFtcCx1bml0cz0ic2VjcyIpIDwgMzEuNSxdKQ0KDQojIHJlbW92aW5nIGNhc2VzIHdpdGggdG90YWwgcmVzcG9uc2UgdGltZSBiZWxvdyAzMS41IHNlY29uZHMNCmlsZCA8LSBpbGRbZGlmZnRpbWUoaWxkJFN1Ym1pc3Npb25UaW1lc3RhbXAsaWxkJFJ1blRpbWVzdGFtcCx1bml0cz0ic2VjcyIpID4gMzEuNSxdDQpgYGANCg0KPGJyPg0KDQojIyMgMS4zLjQuIENvbXBsaWFuY2UgcmF0ZSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KRmluYWxseSwgd2UgaW5zcGVjdCB0aGUgcGFydGljaXBhbnRzJyBjb21wbGlhbmNlIHJhdGUgYW5kIGFwcGx5IG91ciBleGNsdXNpb24gY3JpdGVyaW9uIGJ5IHJlbW92aW5nIGFsbCBwYXJ0aWNpcGFudHMgd2l0aCBsZXNzIHRoYW4gMiB2YWxpZCBvYnNlcnZhdGlvbnMgcGVyIGRheS4gRmlyc3QsIHdlIHVzZSBhIGZvci1sb29wIHRvIGNvbXB1dGUgdGhlIHJlc3BvbnNlIHJhdGUgb2YgZWFjaCBwYXJ0aWNpcGFudCAoaS5lLiwgcGVyY2VudGFnZSBvZiBzdWJtaXR0ZWQgcmVzcG9uc2VzIG92ZXIgdGhlIDE4IHNjaGVkdWxlZCBxdWVzdGlvbm5haXJlcyBmb3IgZWFjaCBwYXJ0aWNpcGFudCkgYW5kLCB3aXRoaW4gdGhhdCBsb29wLCB3ZSBjb21wdXRlIHRoZSB0b3RhbCBudW1iZXIgb2Ygc3VibWl0dGVkIHJlc3BvbnNlcyBmb3IgZWFjaCBwYXJ0aWNpcGFudC1ieS1kYXkgY291cGxlLCBhZGRpbmcgdGhlc2UgdmFyaWFibGVzIHRvIHRoZSBgcHJlbHFzYCBkYXRhc2V0LiBTZWNvbmQsIHdlIHBsb3QgdGhlIGNyZWF0ZWQgcmVzcG9uc2UgcmF0ZSB2YXJpYWJsZXMuIEZpbmFsbHksIHdlIGV4Y2x1ZGUgcGFydGljaXBhbnRzIHdpdGggbGVzcyB0aGFuIDIgcmVzcG9uc2VzIHBlciBkYXkuDQpgYGB7ciAgZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9M30NCiMgY29tcHV0aW5nIG92ZXJhbGwgYW5kIGRhaWx5IGNvbXBsaWFuY2UgcmF0ZQ0KZm9yKGkgaW4gMTpucm93KHByZWxxcykpeyAjIE5vLiByZXNwb25zZXMgb3ZlciB0b3RhbCBudW1iZXIgb2Ygc2NoZWR1bGVkIGRhdGEgcG9pbnRzIChuID0gMTgpDQogIHByZWxxc1tpLCJjb21wUmF0ZSJdIDwtIDEwMCpucm93KGlsZFtpbGQkSUQ9PWFzLmNoYXJhY3RlcihwcmVscXNbaSwiSUQiXSksXSkvMTgNCiAgZm9yKGRheSBpbiAxOjMpeyAjIGNvbXB1dGluZyBudW1iZXIgb2Ygbm9ubWlzc2luZyBkYXRhIHBvaW50cyBwZXIgZWFjaCBkYXkNCiAgICBwcmVscXNbaSxwYXN0ZTAoIm4uZGF5IixkYXkpXSA8LSBucm93KGlsZFtpbGQkSUQ9PWFzLmNoYXJhY3RlcihwcmVscXNbaSwiSUQiXSkgJiBpbGQkZGF5PT1kYXksXSkgfX0NCg0KIyBwbG90dGluZyBvcmlnaW5hbCBjb21wbGlhbmNlDQpwYXIobWZyb3c9YygxLDQpKQ0KZm9yKGkgaW4gYygiY29tcFJhdGUiLCJuLmRheTEiLCJuLmRheTIiLCJuLmRheTMiKSl7IGhpc3QocHJlbHFzWyxpXSxtYWluPWkpIH0NCg0KIyBleGNsdWRpbmcgcGFydGljaXBhbnRzIHdpdGggbGVzcyB0aGFuIDIgdmFsaWQgZGF0YSBwb2ludHMgcGVyIGRheQ0KTjIgPC0gbnJvdyhwcmVscXMpOyBOMSA8LSBucm93KGlsZCkgIyBzYXZpbmcgb3JpZ2luYWwgc2FtcGxlIHNpemVzIGZvciBjb21wYXJpc29uDQpwcmVscXMgPC0gcHJlbHFzW3ByZWxxcyRuLmRheTEgPj0gMiAmIHByZWxxcyRuLmRheTIgPj0gMiAmIHByZWxxcyRuLmRheTMgPj0gMixdICMgZXhjbHVkaW5nIHBhcnRpY2lwYW50cyBmcm9tIHByZWxxcw0KaWxkIDwtIGlsZFtpbGQkSUQgJWluJSBhcy5jaGFyYWN0ZXIocHJlbHFzJElEKSxdDQpjYXQoIlJlbW92ZWQiLE4yLW5yb3cocHJlbHFzKSwicGFydGljaXBhbnRzICgiLHJvdW5kKDEwMCooTjItbnJvdyhwcmVscXMpKS9OMiwxKSwNCiAgICAiJSApIGFuZCIsTjEtbnJvdyhpbGQpLCJvYnNlcnZhdGlvbnMgKCIscm91bmQoMTAwKihOMS1ucm93KGlsZCkpL04xLDEpLCIlICkiKQ0KDQojIHBsb3R0aW5nIHVwZGF0ZWQgY29tcGxpYW5jZQ0KcGFyKG1mcm93PWMoMSw0KSkNCmZvcihpIGluIGMoImNvbXBSYXRlIiwibi5kYXkxIiwibi5kYXkyIiwibi5kYXkzIikpeyBoaXN0KHByZWxxc1ssaV0sbWFpbj1pKSB9DQpgYGANCg0KPGJyPg0KDQojIyMgMS4zLjUuIEV4Y2x1ZGVkIGRhdGENCg0KSGVyZSwgd2UgY29tcHV0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIGV4Y2x1ZGVkIG9ic2VydmF0aW9ucyBhbmQgcGFydGljaXBhbnRzIGJ5IGNvbXBhcmluZyB0aGUgb3JpZ2luYWwgc2FtcGxlIHNpemVzIHdpdGggdGhvc2Ugb2J0YWluZWQgYWZ0ZXIgYXBwbHlpbmcgYWxsIGRhdGEgY2xlYW5pbmcgcHJvY2VkdXJlcy4NCmBgYHtyICB9DQojIHJlc2V0dGluZyBJRCBsZXZlbHMNCmlsZCRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGlsZCRJRCkpDQpwcmVscXMkSUQgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihwcmVscXMkSUQpKQ0KDQojIHRvdGFsIG51bWJlciBhbmQgcGVyY2VudGFnZSBvZiBleGNsdWRlZCBwYXJ0aWNpcGFudHMNCm4yIC0gbmxldmVscyhpbGQkSUQpOyAxMDAqKG4yIC0gbGVuZ3RoKHRhYmxlKGlsZCRJRCkpKS9uMg0KDQojIHRvdGFsIG51bWJlciBhbmQgcGVyY2VudGFnZSBvZiBleGNsdWRlZCBvYnNlcnZhdGlvbnMNCm4xIC0gbnJvdyhpbGQpOyAxMDAqKG4xIC0gbnJvdyhpbGQpKS9uMQ0KYGBgDQoNCjxicj4NCg0KIyMgMS40LiBEYXRhIG1lcmdpbmcgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCkhlcmUsIHdlIG1lcmdlIHRoZSB0aW1lLWludmFyaWFudCBkYXRhIGluY2x1ZGVkIGluIHRoZSB3aWRlLWZvcm0gYHByZWxxc2AgZGF0YXNldCAoaS5lLiwgcGFydGljaXBhbnRzJyBgYWdlYCBhbmQgYGdlbmRlcmApIHdpdGggdGhlIHRpbWUtdmFyeWluZyBkYXRhIGluY2x1ZGVkIGluIHRoZSBsb25nLWZvcm0gYGlsZGAgZGF0YXNldC4gVGhpcyBpcyBkb25lIHdpdGggdGhlIGBqb2luKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBwbHlyYCBwYWNrYWdlIGJhc2VkIG9uIHRoZSBzaGFyZWQgdmFyaWFibGUgYElEYCwgaWRlbnRpZnlpbmcgYWxsIHRoZSBkYXRhIHBvaW50cyBhc3NvY2lhdGVkIHdpdGggdGhlIHNhbWUgcGFydGljaXBhbnQuDQpgYGB7ciAgfQ0KIyBkYXRhIG1lcmdpbmcNCmxpYnJhcnkocGx5cikgIyBvcGVuaW5nIHBseXIgcGFja2FnZSB0byB1c2UgdGhlIGpvaW4oKSBmdW5jdGlvbg0KaWxkIDwtIGpvaW4oaWxkLCAjIGxvbmctZm9ybSBkYXRhc2V0DQogICAgICAgICAgICBwcmVscXNbLGMoIklEIiwiYWdlIiwiZ2VuZGVyIildLCAjIHNlbGVjdGluZyBjb2x1bW5zIGZyb20gdGhlIHdpZGUtZm9ybSBkYXRhc2V0DQogICAgICAgICAgICBieSA9ICJJRCIpICMgc2V0dGluZyB0aGUgY29sdW1uIHNoYXJlZCBieSB0aGUgdHdvIGRhdGFzZXRzDQoNCiMgc2hvd2luZyBzb21lIGNvbHVtbnMgZnJvbSB0aGUgbWVyZ2VkIGRhdGFzZXQNCmlsZFssYygiSUQiLCJhZ2UiLCJnZW5kZXIiLCJkYXkiLCJiZWVwIiwidjEiKV0NCmBgYA0KDQo8YnI+DQoNCiMjIDEuNS4gRGF0YSBjZW50ZXJpbmcgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCkhlcmUsIHdlIGNlbnRlciBhbnkgdGltZS12YXJ5aW5nIHZhcmlhYmxlIChpLmUuLCBFU00gaXRlbSBzY29yZXMgc3VjaCBhcyBgdjFgKSBieSBjb21wdXRpbmcgdGhlIGNvcnJlc3BvbmRpbmcgY2x1c3Rlci1tZWFuIChlLmcuLCBgdjFfbWVhbmApIGFuZCBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGUgKGUuZy4sIGB2MV9jbWNgKSAoc2VlIHNlZSBbSGFtYWtlciAmIEdyYXNtYW4sIDIwMTVdKCNyZWYpOyBbV2FuZyAmIE1heHdlbGwsIDIwMTVdKCNyZWYpKS4gU2luY2UgaW4gUiB0aGUgc2FtZSByZXN1bHQgY2FuIGJlIGFjaGlldmVkIGluIG11bHRpcGxlIHdheXMsIHNvbWUgb2Ygd2hpY2ggbWlnaHQgYmUgbW9yZSBpbnR1aXRpdmUgZm9yIHNvbWUgdXNlcnMgYnV0IG5vdCBmb3Igb3RoZXJzLCB0aGlzIHN0ZXAgaXMgaW1wbGVtZW50ZWQgaW4gdHdvIGRpZmZlcmVudCB3YXlzLCBuYW1lbHkgdXNpbmcgYGJhc2VgIFIgYW5kIHdpdGggdGhlIGB0aWR5dmVyc2VgIHN5bnRheC4NCg0KIyMjIEJhc2UgUg0KDQpXaXRoIGBiYXNlYCBSLCBjbHVzdGVyIG1lYW5zIChuYW1lZCAidmFyaWFibGVfbWVhbiIpIGFyZSBjb21wdXRlZCB1c2luZyB0aGUgYGFnZ3JlZ2F0ZWAgZnVuY3Rpb24sIHdoaWNoIGFsbG93cyB0byBjb21wdXRlIHRoZSBtZWFuIG9mIG9uZSBvciBtb3JlIHZhcmlhYmxlcyAoaGVyZSwgdGhlIG5lZ2F0aXZlIHZhbGVuY2UsIHRhc2sgZGVtYW5kLCBhbmQgdGFzayBjb250cm9sIGl0ZW0gc2NvcmVzKSBiYXNlZCBvbiBhIGdyb3VwaW5nIHZhcmlhYmxlIChoZXJlLCB0aGUgcGFydGljaXBhbnQgaWRlbnRpZmllciB2YXJpYWJsZSBgSURgKS4gVGhlbiwgd2UgYWRkIGNsdXN0ZXIgbWVhbnMgdG8gdGhlIGBpbGRgIGxvbmctZm9ybSBkYXRhc2V0IGFuZCB3ZSB1c2UgYSBmb3ItbG9vcCBmb3IgY29tcHV0aW5nIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCBzY29yZXMgKG5hbWVkICJ2YXJpYWJsZV9jbWMiKSBieSBzdWJ0cmFjdGluZyBjbHVzdGVyLW1lYW4gdmFsdWVzIGZyb20gdGhlIG9yaWdpbmFsIHZhcmlhYmxlIHZhbHVlcywgZm9yIGVhY2ggdGltZS12YXJ5aW5nIHZhcmlhYmxlLg0KYGBge3IgIH0NCiMgc2VsZWN0aW5nIHZhcmlhYmxlIG5hbWVzDQpWYXJOYW1lcyA8LSBjKCJ2MSIsInYyIiwidjMiLCJkMSIsImQyIiwiZDMiLCJkNCIsImMxIiwiYzIiLCJjMyIpDQoNCiMgY29tcHV0aW5nIGNsdXN0ZXItbWVhbiB2YWx1ZXMgb2YgdGltZS12YXJ5aW5nIHZhcmlhYmxlcw0KbWVhbnMgPC0gYWdncmVnYXRlKHggPSBpbGRbLFZhck5hbWVzXSwgIyB2YXJpYWJsZXMgdG8gYmUgYWdncmVnYXRlZA0KICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdChpbGQkSUQpLCAjIGNsdXN0ZXIgdmFyaWFibGUgKGl0IHNob3VsZCBiZSBhIGxpc3QpDQogICAgICAgICAgICAgICAgICAgRlVOID0gbWVhbikgIyBhZ2dyZWdhdGluZyBmdW5jdGlvbiAobWVhbikNCmNvbG5hbWVzKG1lYW5zKSA8LSBjKCJJRCIsICMgcmVuYW1pbmcgdmFyaWFibGVzIHRvIGF2b2lkIGR1cGxpY2F0ZWQgbmFtZXMgYmVsb3cNCiAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChWYXJOYW1lcywiX21lYW4iKSkNCg0KIyBqb2luaW5nIGNsdXN0ZXIgbWVhbnMgdG8gdGhlIGxvbmctZm9ybSBkYXRhc2V0DQppbGQgPC0gcGx5cjo6am9pbihpbGQsbWVhbnMsYnk9IklEIikNCg0KIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHZhbHVlcw0KZm9yKFZhck5hbWUgaW4gVmFyTmFtZXMpeyAjIGZvciBlYWNoIHRpbWUtdmFyeWluZyB2YXJpYWJsZQ0KICBpbGRbLHBhc3RlMChWYXJOYW1lLCJfY21jIildIDwtICMgdGhlIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCB2YXJpYWJsZSAoX2NtYykuLi4NCiAgICBpbGRbLFZhck5hbWVdIC0gIyAuLi5pcyBlcXVhbCB0byB0aGUgb3JpZ2luYWwgdmFyaWFibGUuLi4NCiAgICBpbGRbLHBhc3RlMChWYXJOYW1lLCJfbWVhbiIpXSB9ICMgLi4ubWludXMgdGhlIGNsdXN0ZXItbWVhbiB2YXJpYWJsZSAoX21lYW4pLg0KDQojIHNob3dpbmcgZXhhbXBsZSB2YXJpYWJsZXMNCmlsZFssYygiSUQiLCJkYXkiLCJiZWVwIiwiYzEiLCJjMV9tZWFuIiwiYzFfY21jIiwiZDEiLCJkMV9tZWFuIiwiZDFfY21jIildDQpgYGANCg0KPGJyPg0KDQojIyMgVGlkeXZlcnNlDQoNCkhlcmUsIHdlIHJlcGxpY2F0ZSB0aGUgc2FtZSBvcGVyYXRpb25zIGluIHRocmVlIGFsdGVybmF0aXZlIHdheXMgYmFzZWQgb24gdGhlIGB0aWR5dmVyc2VgIHN5bnRheCAoc2VlIFtXaWNraGFtIGV0IGFsLiwgMjAyM10oI3JlZikpLiBJbiBvcHRpb24gQSwgd2UgdXNlIHRoZSBwaXBlIG9wZXJhdG9yIGAlPiVgIHRvIGNvbmNhdGVuYXRlIG9wZXJhdGlvbnMsIHRoZSBgZ3JvdXBfYnlgIGZ1bmN0aW9uIHRvIGdyb3VwIG9wZXJhdGlvbnMgYnkgcGFydGljaXBhbnQgYElEYCwgYW5kIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBzcGVjaWZ5IHdoaWNoIG9wZXJhdGlvbnMgc2hvdWxkIGJlIGFwcGxpZWQgKGkuZS4sIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gYW5kIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCB2YWx1ZXMpLiBJbiBvcHRpb24gQiwgd2UgZGlyZWN0bHkgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBzcGVjaWZ5IGJvdGggdGhlIG9wZXJhdGlvbnMgdG8gYmUgYXBwbGllZCBhbmQgdGhlIGdyb3VwaW5nIHZhcmlhYmxlIChzcGVjaWZpZWQgd2l0aCB0aGUgYXJndW1lbnQgYC5ieWApLiBGaW5hbGx5LCBvcHRpb24gQyBpcyBhbiBleHRlbnNpb24gb2Ygb3B0aW9uIEIgd2hlcmUgd2UgdXNlIHRoZSBgYWNyb3NzYCBmdW5jdGlvbiB0byByZXBlYXQgdGhlIG9wZXJhdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgLmZuc2AgYXJndW1lbnQgYWNyb3NzIGFsbCB0aGUgY29sdW1ucyBzcGVjaWZpZWQgaW4gdGhlIGAuY29sc2AgYXJndW1lbnQgb2YgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uLiBJbiB0aGlzIHdheSwgaXQgaXMgcG9zc2libGUgdG8gYXZvaWQgbWFudWFsbHkgcmV3cml0aW5nIHRoZSBzYW1lIG9wZXJhdGlvbnMgZm9yIGVhY2ggdmFyaWFibGUsIGFzIGluIG9wdGlvbiBBIGFuZCBCLiANCmBgYHtyICBlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCiMgdGhpcyBpcyBqdXN0IHRvIGF2b2lkIG91dHB1dHRpbmcgbG9uZyB0ZXh0IG1lc3NhZ2Ugd2hlbiBsb2FkaW5nIHRoZSBwYWNrYWdlDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KYGBge3IgIH0NCiMgbG9hZGluZyB0aWR5dmVyc2UgcGFja2FnZSBjb2xsZWN0aW9uDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBvcHRpb24gQTogbXV0YXRlIGFuZCBncm91cF9ieQ0KaWxkX3RpZHl2ZXJzZV9BIDwtIA0KICBpbGQgJT4lDQogIGdyb3VwX2J5KElEKSAlPiUgIyBncm91cGluZyBvcGVyYXRpb25zIGJ5IGNsdXN0ZXIgdmFyaWFibGUgIklEIg0KICBtdXRhdGUoYzFfbWVhbiA9IG1lYW4oYzEpLCAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gdmFyaWFibGVzIChvbmx5IGV4YW1wbGVzKQ0KICAgICAgICAgZDFfbWVhbiA9IG1lYW4oZDEpLA0KICAgICAgICAgYzFfY21jID0gYzEgLSBjMV9tZWFuLCAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGUgKG9ubHkgZXhhbXBsZXMpDQogICAgICAgICBkMV9jbWMgPSBkMSAtIGQxX21lYW4pIA0KaWxkX3RpZHl2ZXJzZV9BWyxjKCJJRCIsImRheSIsImJlZXAiLCJjMSIsImMxX21lYW4iLCJjMV9jbWMiLCJkMSIsImQxX21lYW4iLCJkMV9jbWMiKV0NCg0KIyBvcHRpb24gQjogbXV0YXRlIHdpdGggIi5ieSINCmlsZF90aWR5dmVyc2VfQiA8LSANCiAgbXV0YXRlKGlsZCwNCiAgICAgICAgIGMxX21lYW4gPSBtZWFuKGMxKSwgIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuIHZhcmlhYmxlcyAob25seSBleGFtcGxlcykNCiAgICAgICAgIGQxX21lYW4gPSBtZWFuKGQxKSwNCiAgICAgICAgIGMxX2NtYyA9IGMxIC0gYzFfbWVhbiwgIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHZhcmlhYmxlIChvbmx5IGV4YW1wbGVzKQ0KICAgICAgICAgZDFfY21jID0gZDEgLSBkMV9tZWFuLA0KICAgICAgICAgLmJ5ID0gSUQpICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCmlsZF90aWR5dmVyc2VfQlssYygiSUQiLCJkYXkiLCJiZWVwIiwiYzEiLCJjMV9tZWFuIiwiYzFfY21jIiwiZDEiLCJkMV9tZWFuIiwiZDFfY21jIildDQoNCiMgb3B0aW9uIEM6IHJlcGVhdCBvcHRpb24gQiBvdmVyIG11bHRpcGxlIGNvbHVtbnMgdXNpbmcgdGhlICJhY3Jvc3MiIGNvbW1hbmQNCmlsZF90aWR5dmVyc2VfQyA8LQ0KICBtdXRhdGUoaWxkLA0KICAgICAgICAgYWNyb3NzKA0KICAgICAgICAgICAjIHNlbGVjdGluZyBhbGwgdGhlIGNvbHVtbnMgb24gd2hpY2ggcmVwZWF0aW5nIHRoZSBvcGVyYXRpb25zDQogICAgICAgICAgIC5jb2xzID0gYygidjEiLCJ2MiIsInYzIiwiZDEiLCJkMiIsImQzIiwiZDQiLCJjMSIsImMyIiwiYzMiKSwgDQogICAgICAgICAgIC5mbnMgPSBsaXN0KCAjIGxpc3Qgb2Ygb3BlcmF0aW9ucyB0byBiZSByZXBlYXRlZA0KICAgICAgICAgICAgIG1lYW4gPX4gbWVhbigueCksICMgY29tcHV0aW5nIGNsdXN0ZXItbWVhbiB2YXJpYWJsZQ0KICAgICAgICAgICAgIGNtYyA9fiAueCAtIG1lYW4oLngpICkpLCAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGUNCiAgICAgICAgIC5ieSA9IElEKSAjIGdyb3VwaW5nIG9wZXJhdGlvbnMgYnkgY2x1c3RlciB2YXJpYWJsZSAiSUQiDQppbGRfdGlkeXZlcnNlX0NbLGMoIklEIiwiZGF5IiwiYmVlcCIsImMxIiwiYzFfbWVhbiIsImMxX2NtYyIsImQxIiwiZDFfbWVhbiIsImQxX2NtYyIpXQ0KYGBgDQoNCjxicj4NCg0KIyMgMS42LiBQc3ljaG9tZXRyaWNzDQoNCkhlcmUsIHdlIGV2YWx1YXRlIHRoZSBwc3ljaG9tZXRyaWMgcHJvcGVydGllcyBvZiB0aGUgY29uc2lkZXJlZCBFU00gdmFyaWFibGVzLg0KDQojIyMgMS42LjEuIEl0ZW0gc2NvcmVzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpGaXJzdCwgd2UgdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YsIGFuZCB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4sIGl0ZW0gc2NvcmVzLiBXZSBjYW4gc2VlIHRoYXQgYWxsIGl0ZW0gc2NvcmVzIHNoYXJlIHRoZSBzYW1lIHJhbmdlICgxLTcpIGFuZCB0aGF0IG1vc3Qgc2NvcmVzIGFyZSBxdWl0ZSBzeW1tZXRyaWNhbGx5IGRpc3RyaWJ1dGVkLCBhbHRob3VnaCB3aXRoIHNvbWUgc2tld2VkIGRpc3RyaWJ1dGlvbnMgKGl0ZW1zIGBjMWAsIGBjMmAsIGFuZCBgYzNgKS4gQmV0dGVyIHN5bW1ldHJ5IGlzIHNob3duIGJ5IGNsdXN0ZXItbWVhbiBhbmQgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHZhbHVlcy4NCmBgYHtyICBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD00fQ0KIyBzZWxlY3RpbmcgaXRlbXMgdG8gYmUgZXZhbHVhdGVkDQppdGVtcyA8LSBjKCJ2MSIsInYyIiwidjMiLCJkMSIsImQyIiwiZDMiLCJkNCIsImMxIiwiYzIiLCJjMyIpDQoNCiMgcGxvdHRpbmcgb3JpZ2luYWwgaXRlbSBzY29yZSBkaXN0cmlidXRpb25zDQpwYXIobWZyb3c9YygyLDUpKQ0KZm9yKGl0ZW0gaW4gaXRlbXMpeyBoaXN0KGlsZFssaXRlbV0sbWFpbj1pdGVtLHhsYWI9IiIsYnJlYWtzPTMwKSB9DQoNCiMgcGxvdHRpbmcgY2x1c3Rlci1tZWFuIHNjb3JlIGRpc3RyaWJ1dGlvbnMNCnBhcihtZnJvdz1jKDIsNSkpDQpmb3IoaXRlbSBpbiBpdGVtcyl7IGhpc3QoaWxkWyFkdXBsaWNhdGVkKGlsZCRJRCkscGFzdGUwKGl0ZW0sIl9tZWFuIildLG1haW49cGFzdGUwKGl0ZW0sIl9tZWFuIikseGxhYj0iIixicmVha3M9MzApIH0NCg0KIyBwbG90dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgc2NvcmUgZGlzdHJpYnV0aW9ucw0KcGFyKG1mcm93PWMoMiw1KSkNCmZvcihpdGVtIGluIGl0ZW1zKXsgaGlzdChpbGRbLHBhc3RlMChpdGVtLCJfY21jIildLG1haW49cGFzdGUwKGl0ZW0sIl9jbWMiKSx4bGFiPSIiLGJyZWFrcz0zMCkgfQ0KYGBgDQoNCkhlcmUsIHdlIGNvbXB1dGUgYW5kIHZpc3VhbGl6ZSB0aGUgbGV2ZWwtc3BlY2lmaWMgemVyby1vcmRlciBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGNvbnNpZGVyZWQgaXRlbXMuIExldmVsLTEgKHdpdGhpbi1pbmRpdmlkdWFsKSBhbmQgbGV2ZWwtMiAoYmV0d2Vlbi1pbmRpdmlkdWFsKSBjb3JyZWxhdGlvbnMgYXJlIGNvbXB1dGVkIGJ5IGNvcnJlbGF0aW5nIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCAoKm4qID0gYHIgbnJvdyhpbGQpYCkgYW5kIGNsdXN0ZXItbWVhbiB2YWx1ZXMgKCpuKiA9IGByIG5yb3cocHJlbHFzKWApLCByZXNwZWN0aXZlbHkuIFdlIGNhbiBzZWUgdGhhdCBjb3JyZWxhdGlvbnMgYXJlIGluIHRoZSBleHBlY3RlZCBkaXJlY3Rpb25zLCB3aXRoIHN0cm9uZ2VyIGNvcnJlbGF0aW9ucyBhdCBsZXZlbCAyIChzaG93biBiZWxvdyB0aGUgbWFpbiBkaWFnb25hbCkgdGhhbiBhdCBsZXZlbCAxIChzaG93biBhYm92ZSB0aGUgbWFpbiBkaWFnb25hbCksIGFuZCBhbW9uZyBpdGVtIHNjb3JlcyBiZWxvbmdpbmcgdG8gdGhlIHNhbWUgc2NhbGUgdGhhbiBhbW9uZyBzY29yZXMgZnJvbSBkaWZmZXJlbnQgc2NhbGVzLg0KYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Nn0NCiMgY29tcHV0aW5nIGxldmVsLTEgY29ycmVsYXRpb25zDQpjb3IxIDwtIHJvdW5kKGNvcihpbGRbLGl0ZW1zXSksMikNCg0KIyBjb21wdXRpbmcgbGV2ZWwtMiBjb3JyZWxhdGlvbnMNCmNvcjIgPC0gcm91bmQoY29yKGlsZFshZHVwbGljYXRlZChpbGQkSUQpLHBhc3RlMChpdGVtcywiX21lYW4iKV0pLDIpDQoNCiMgdmlzdWFsaXppbmcgY29ycmVsYXRpb25zDQpsaWJyYXJ5KHBzeWNoKQ0KY29yMVtsb3dlci50cmkoY29yMSldIDwtIGNvcjJbbG93ZXIudHJpKGNvcjIpXSAjIG1lcmdpbmcgdGhlIHR3byBtYXRyaWNlcw0KY29yUGxvdChjb3IxKSAjIHBsb3R0aW5nIGNvcnJlbGF0aW9uIG1hdHJpeA0KYGBgDQoNCjxicj4NCg0KIyMjIDEuNi4yLiBSZWxpYWJpbGl0eSBpbmRpY2VzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpIZXJlLCB3ZSBjb21wdXRlIHJlbGlhYmlsaXR5IGluZGljZXMgYmFzZWQgb24gZ2VuZXJhbGl6YWJpbGl0eSB0aGVvcnksIHRoYXQgaXMgYnkgZml0dGluZyBhIHJhbmRvbS1pbnRlcmNlcHQtb25seSBtb2RlbCB0byBkZWNvbXBvc2UgdGhlIHZhcmlhbmNlIGluIGl0ZW0gc2NvcmVzIGJhc2VkIG9uIHBhcnRpY2lwYW50cywgaXRlbXMsIHRpbWUsIGFuZCB0aGVpciBpbnRlcmFjdGlvbnMgKHNlZSBbU2hyb3V0ICYgTGFuZSAoMjAxMildKCNyZWYpOyBbQ3JhbmZvcmQgZXQgYWwuLCAyMDA2XSgjcmVmKSkuIFRoaXMgaXMgZG9uZSB1c2luZyB0aGUgYG11bHRpbGV2ZWwucmVsaWFiaWxpdHkoKWAgZnVuY3Rpb24gZnJvbSB0aGUgYHBzeWNoYCBwYWNrYWdlLg0KYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Nn0NCiMgaXNvbGF0aW5nIGZvY3VzZWQgaXRlbXMNCml0ZW1zIDwtIGMoInYxIiwidjIiLCJ2MyIpDQoNCiMgY3JlYXRpbmcgdmFyaWFibGUgJ3RpbWUnIChqb2luaW5nIGRheSBhbmQgYmVlcCkNCmlsZCR0aW1lIDwtIHBhc3RlKGlsZCRkYXksIGlsZCRiZWVwKQ0KDQojIGNvbXB1dGluZyByZWxpYWJpbGl0eSBpbmRpY2VzIGZvciBuZWdhdGl2ZSB2YWxlbmNlIGl0ZW1zDQptdWx0aWxldmVsLnJlbGlhYmlsaXR5KHggPSBpbGQsICMgbG9uZy1mb3JtIGRhdGFzZXQNCiAgICAgICAgICAgICAgICAgICAgICAgZ3JwID0gIklEIiwgIyBjbHVzdGVyIHZhcmlhYmxlIChjYXRlZ29yaWNhbCkNCiAgICAgICAgICAgICAgICAgICAgICAgVGltZSA9ICJ0aW1lIiwgIyB0aW1lIHZhcmlhYmxlIChjYXRlZ29yaWNhbCkNCiAgICAgICAgICAgICAgICAgICAgICAgaXRlbXMgPSBpdGVtcywgIyBpdGVtIG5hbWVzDQogICAgICAgICAgICAgICAgICAgICAgIGxtZXIgPSBUUlVFLCBhb3YgPSBGQUxTRSAjIGFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIGJlIGluY2x1ZGVkDQogICAgICAgICAgICAgICAgICAgICAgIClbYygiUmtGIiwgIlJjIildICMgc2VsZWN0aW5nIHRoZSB0YXJnZXQgY29lZmZpY2llbnRzDQoNCiMgcmVsaWFiaWxpdHkgaW5kaWNlcyBmb3IgdGFzayBkZW1hbmRzDQptdWx0aWxldmVsLnJlbGlhYmlsaXR5KGlsZCwgZ3JwPSJJRCIsIFRpbWU9InRpbWUiLCBpdGVtcz1jKCJkMSIsImQyIiwiZDMiLCJkNCIpLGxtZXI9VFJVRSwgYW92PUZBTFNFKVtjKCJSa0YiLCJSYyIpXQ0KDQojIHJlbGlhYmlsaXR5IGluZGljZXMgZm9yIHRhc2sgY29udHJvbA0KbXVsdGlsZXZlbC5yZWxpYWJpbGl0eShpbGQsIGdycD0iSUQiLCBUaW1lPSJ0aW1lIiwgaXRlbXM9YygiYzEiLCJjMiIsImMzIiksbG1lcj1UUlVFLCBhb3Y9RkFMU0UpW2MoIlJrRiIsIlJjIildDQpgYGANCg0KPGJyPg0KDQojIyMgMS42LjMuIE1DRkENCg0KSGVyZSwgd2UgcHJvdmlkZSBzb21lIGlsbHVzdHJhdGl2ZSBjb2RlIGV4ZW1wbGlmeWluZyBhIHdheSB0byBjb25kdWN0IGEgbXVsdGlsZXZlbCBjb25maXJtYXRvcnkgZmFjdG9yIGFuYWx5c2lzIChNQ0ZBKSBvZiB0aGUgY29uc2lkZXJlZCBpdGVtcywgYmFzZWQgb24gW0phY2sgJiBKb3JnZW5zZW4gKDIwMTcpXSgjcmVmKS4gU3BlY2lmaWNhbGx5LCB3ZSBmaXQgYW5kIGNvbXBhcmUgYSBjb25maWd1cmFsIG1vZGVsIGBmaXQuY29uZmAgKHdpdGggdGhlIHNhbWUgZmFjdG9yIHN0cnVjdHVyZSBhY3Jvc3MgbGV2ZWxzKSBhbmQgYSB3ZWFrLWludmFyaWFuY2UgbW9kZWwgYGZpdC53aW52YCAod2l0aCBib3RoIHRoZSBzYW1lIHN0cnVjdHVyZSBhbmQgZXF1aXZhbGVudCBmYWN0b3IgbG9hZGluZ3MgYWNyb3NzIGxldmVscykuIFdlIGNhbiBzZWUgdGhhdCB0aGUgdHdvIG1vZGVscyBmaXQgdGhlIGRhdGEgY29tcGFyYWJseSwgYW5kIHdlIHRydXN0IHRoZSB3ZWFrLWludmFyaWFuY2UgbW9kZWwgYGZpdC53aW52YC4NCmBgYHtyIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCiMgbW9kZWwgc3BlY2lmaWNhdGlvbjogY29uZmlndXJhbCBtb2RlbCAoc2FtZSBzdHJ1Y3R1cmUgYWNyb3NzIGxldmVscykNCm0uY29uZiA8LSAnbGV2ZWw6IDENCiAgICAgICAgICAgTmVnVmFsX3cgPX4gdjEgKyB2MiArIHYzDQogICAgICAgICAgIHRhc2tEZW1fdyA9fiBkMSArIGQyICsgZDMgKyBkNA0KICAgICAgICAgICB0YXNrQ29uX3cgPX4gYzEgKyBjMiArIGMzDQogICAgICAgICAgIA0KICAgICAgICAgICBsZXZlbDogMg0KICAgICAgICAgICBOZWdWYWxfYiA9fiB2MSArIHYyICsgdjMNCiAgICAgICAgICAgdGFza0RlbV9iID1+IGQxICsgZDIgKyBkMyArIGQ0DQogICAgICAgICAgIHRhc2tDb25fYiA9fiBjMSArIGMyICsgYzMnDQoNCiMgbW9kZWwgc3BlY2lmaWNhdGlvbjogd2Vhay1pbnZhcmlhbmNlIG1vZGVsIChzYW1lIHN0cnVjdHVyZSBhbmQgbG9hZGluZ3MgYWNyb3NzIGxldmVscykNCm0ud2ludiA8LSAnbGV2ZWw6IDENCiAgICAgICAgICAgTmVnVmFsX3cgPX4gYSp2MSArIGIqdjIgKyBjKnYzDQogICAgICAgICAgIHRhc2tEZW1fdyA9fiBkKmQxICsgZSpkMiArIGYqZDMgKyBnKmQ0DQogICAgICAgICAgIHRhc2tDb25fdyA9fiBoKmMxICsgaSpjMiArIGoqYzMNCiAgICAgICAgICAgDQogICAgICAgICAgIGxldmVsOiAyDQogICAgICAgICAgIE5lZ1ZhbF9iID1+IGEqdjEgKyBiKnYyICsgYyp2Mw0KICAgICAgICAgICB0YXNrRGVtX2IgPX4gZCpkMSArIGUqZDIgKyBmKmQzICsgZypkNA0KICAgICAgICAgICB0YXNrQ29uX2IgPX4gaCpjMSArIGkqYzIgKyBqKmMzDQogICAgICAgICAgICcNCg0KIyBtb2RlbCBmaXQgKG5vdGU6IHNvbWUgcGFydGljaXBhbnRzIHNob3cgbm8gdmFyaWFuY2UgaW4gc29tZSBpdGVtcywgd2hpY2ggaXMgcXVpdGUgY29tbW9uKQ0KbGlicmFyeShsYXZhYW4pDQpmaXQuY29uZiA8LSBjZmEobW9kZWwgPSBtLmNvbmYsIGRhdGEgPSBpbGQsIGNsdXN0ZXI9IklEIiwgc3RkLmx2PVRSVUUpDQpmaXQud2ludiA8LSBjZmEobW9kZWwgPSBtLndpbnYsIGRhdGEgPSBpbGQsIGNsdXN0ZXI9IklEIiwgc3RkLmx2PVRSVUUpDQoNCiMgZml0IGluZGljZXMNCnJvdW5kKGxhdkluc3BlY3QoZml0LmNvbmYsIHdoYXQgPSAiZml0IilbYygicm1zZWEiLCJjZmkiLCJzcm1yX3dpdGhpbiIsInNybXJfYmV0d2VlbiIpXSwzKSAjIGNvbmZpZ3VyYWwNCnJvdW5kKGxhdkluc3BlY3QoZml0LndpbnYsIHdoYXQgPSAiZml0IilbYygicm1zZWEiLCJjZmkiLCJzcm1yX3dpdGhpbiIsInNybXJfYmV0d2VlbiIpXSwzKSAjIHdlYWsgaW52YXJpYW5jZQ0KYGBgDQoNClRoZSBpbnNwZWN0aW9uIG9mIHRoZSBzdGFuZGFyZGl6ZWQgcGFyYW1ldGVycyBlc3RpbWF0ZWQgYnkgdGhlIHdlYWstaW52YXJpYW5jZSBtb2RlbCByZXZlYWxzIHNpZ25pZmljYW50IGZhY3RvciBsb2FkaW5ncyByYW5naW5nIGZyb20gYHIgcm91bmQobWluKHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdC53aW52KVtzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQud2ludikkb3A9PSI9fiIsImVzdC5zdGQiXSksMilgIHRvIGByIHJvdW5kKG1heChzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQud2ludilbc3RhbmRhcmRpemVkc29sdXRpb24oZml0LndpbnYpJG9wPT0iPX4iLCJlc3Quc3RkIl0pLDIpYC4gVGhlIG1vZGVsIGFsc28gZXN0aW1hdGVzIHNpZ25pZmljYW50IGNvcnJlbGF0aW9ucyBhbW9uZyBsYXRlbnQgdmFyaWFibGVzIGluIHRoZSBleHBlY3RlZCBkaXJlY3Rpb25zLCB3aXRoIHRoZSBvbmx5IGV4Y2VwdGlvbiBvZiB0aGF0IGJldHdlZW4gZGVtYW5kcyBhbmQgY29udHJvbCBhdCBsZXZlbCAyIChub3Qgc2lnbmlmaWNhbnQpLiBPdmVyYWxsLCB0aGVzZSByZXN1bHRzIHN1cHBvcnQgdGhlIHZhbGlkaXR5IG9mIHRoZSBtZWFzdXJlbWVudCBtb2RlbCBoeXBvdGhlc2l6ZWQgZm9yIHRoZSBjb25zaWRlcmVkIGl0ZW1zLg0KYGBge3IgfQ0KIyBmYWN0b3IgbG9hZGluZ3MgZnJvbSB0aGUgc2VsZWN0ZWQgbW9kZWwgKHdlYWsgaW52YXJpYW5jZSkNCnAgPC0gc3RhbmRhcmRpemVkc29sdXRpb24oZml0LndpbnYpICMgc3RhbmRhcmRpemVkIGNvZWZmaWNpZW50cw0KcFtwJG9wPT0iPX4iLF0gIyBzZWxlY3RpbmcgZmFjdG9yIGxvYWRpbmdzDQoNCiMgY29ycmVsYXRpb25zIGFtb25nIGxhdGVudCBmYWN0b3JzDQpwW3AkbGhzJWluJWMoIk5lZ1ZhbF93IiwidGFza0RlbV93IiwidGFza0Nvbl93IikgJiBwJGxocyAhPSBwJHJocyAmIHAkb3A9PSJ+fiIsXSAjIGxldmVsIDENCnBbcCRsaHMlaW4lYygiTmVnVmFsX2IiLCJ0YXNrRGVtX2IiLCJ0YXNrQ29uX2IiKSAmIHAkbGhzICE9IHAkcmhzICYgcCRvcD09In5+IixdICMgbGV2ZWwgMg0KYGBgDQoNCjxicj4NCg0KIyMjIDEuNi40LiBMZXZlbC1zcGVjaWZpYyByZWxpYWJpbGl0eSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KRmluYWxseSwgd2UgdXNlIHRoZSBNQ0ZBIG1vZGVsIHNlbGVjdGVkIGFib3ZlIHRvIGNvbXB1dGUgbGV2ZWwtc3BlY2lmaWMgTWNEb25hbGQncyAkXG9tZWdhJCBjb2VmZmljaWVudHMgZm9yIGVhY2ggc2NhbGUgKHNlZSBbR2VsZGhvZiBldCBhbC4gMjAxNF0oI3JlZikpLiBXZSBjYW4gc2VlIHRoYXQgYWxsICRcb21lZ2EkIGNvZWZmaWNpZW50cyBhcmUgc2F0aXNmYWN0b3J5IHdpdGggdmFsdWVzIGhpZ2hlciB0aGFuIDAuNzAgYW5kIGhpZ2hlciBjb2VmZmljaWVudHMgYXQgbGV2ZWwgMiB0aGFuIGF0IGxldmVsIDEuDQpgYGB7ciB9DQojIG9tZWdhIHdpdGhpbiBuZWdhdGl2ZSB2YWxlbmNlDQpzbCA8LSBwW3Akb3A9PSI9fiIgJiBzdWJzdHIocCRyaHMsMSwxKT09InYiLCJlc3Quc3RkIl1bMTozXSAjIHNlbGVjdGluZyBmYWN0b3IgbG9hZGluZ3MgYXQgbGV2ZWwgMQ0Kcm91bmQoIHN1bShzbCleMiAvICMgb21lZ2EgPSBzdW0gb2Ygc3F1YXJlZCBsb2FkaW5ncyAvDQogICAgICAgICAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpICMgKHN1bSBvZiBzcXVhcmVkIGxvYWRpbmdzICsgcmVzaWR1YWwgdmFyaWFuY2VzKQ0KDQojIG9tZWdhIHdpdGhpbiAtIHRhc2sgZGVtYW5kcw0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJkIiwiZXN0LnN0ZCJdWzE6NF0NCnJvdW5kKCBzdW0oc2wpXjIgLyAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpIA0KDQojIG9tZWdhIHdpdGhpbiAtIHRhc2sgY29udHJvbA0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJjIiwiZXN0LnN0ZCJdWzE6M10gDQpyb3VuZCggc3VtKHNsKV4yIC8gKHN1bShzbCleMiArIHN1bSgxIC0gc2xeMikpICwyKSANCg0KIyBvbWVnYSBiZXR3ZWVuIC0gbmVnYXRpdmUgdmFsZW5jZQ0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJ2IiwiZXN0LnN0ZCJdWzQ6Nl0NCnJvdW5kKCBzdW0oc2wpXjIgLyAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpIA0KDQojIG9tZWdhIGJldHdlZW4gLSB0YXNrIGRlbWFuZHMNCnNsIDwtIHBbcCRvcD09Ij1+IiAmIHN1YnN0cihwJHJocywxLDEpPT0iZCIsImVzdC5zdGQiXVs1OjZdIA0Kcm91bmQoIHN1bShzbCleMiAvIChzdW0oc2wpXjIgKyBzdW0oMSAtIHNsXjIpKSAsMikgDQoNCiMgb21lZ2EgYmV0d2VlbiAtIHRhc2sgY29udHJvbA0Kc2wgPC0gcFtwJG9wPT0iPX4iICYgc3Vic3RyKHAkcmhzLDEsMSk9PSJjIiwiZXN0LnN0ZCJdWzQ6Nl0NCnJvdW5kKCBzdW0oc2wpXjIgLyAoc3VtKHNsKV4yICsgc3VtKDEgLSBzbF4yKSkgLDIpIA0KYGBgDQoNCk9mIG5vdGUsIHRoZSBzYW1lIGNvZWZmaWNpZW50cyBjYW4gYmUgb2J0YWluZWQgbW9yZSBlZmZlY3RpdmVseSAoaS5lLiwgd2l0aG91dCBmaXR0aW5nIE1DRkEgbW9kZWxzKSBieSB1c2luZyB0aGUgYG9tZWdhU0VNYCBmdW5jdGlvbiBvZiB0aGUgYG11bHRpbGV2ZWxUb29sc2AgcGFja2FnZS4NCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQojIGxvYWRpbmcgbXVsdGlsZXZlbFRvb2xzIGxpYnJhcnkNCmxpYnJhcnkobXVsdGlsZXZlbFRvb2xzKQ0KDQojIE5lZ2F0aXZlIHZhbGVuY2UNCm9tZWdhU0VNKGl0ZW1zPXBhc3RlMCgidiIsMTozKSwgaWQgPSJJRCIsIGRhdGE9aWxkKSRSZXN1bHRzDQoNCiMgVGFzayBkZW1hbmQNCm9tZWdhU0VNKGl0ZW1zPXBhc3RlMCgiZCIsMTo0KSwgaWQgPSJJRCIsIGRhdGE9aWxkKSRSZXN1bHRzDQoNCiMgVGFzayBjb250cm9sDQpvbWVnYVNFTShpdGVtcz1wYXN0ZTAoImMiLDE6MyksIGlkID0iSUQiLCBkYXRhPWlsZCkkUmVzdWx0cw0KYGBgDQoNCjxicj4NCg0KIyMgMS43LiBDb21wb3NpdGUgc2NvcmVzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQpIZXJlLCB3ZSBjb21wdXRlIHRoZSBjb21wb3NpdGUgc2NvcmVzIGZvciBlYWNoIHNjYWxlIGJ5IGF2ZXJhZ2luZyB0aGUgY29ycmVzcG9uZGluZyBpdGVtIHNjb3Jlcy4gVGhlbiB3ZSBjb21wdXRlIHRoZSBjbHVzdGVyLW1lYW4gYW5kIHRoZSBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmVyc2lvbnMgb2YgdGhlIGNvbXBvc2l0ZSBzY29yZXMgdXNpbmcgdGhlIHNhbWUgcHJvY2VkdXJlcyBzaG93biBpbiBTdGVwIDUuICBBcyBkb25lIGFib3ZlLCB3ZSBzaG93IGhvdyB0byBpbXBsZW1lbnQgdGhpcyBzdGVwIGJ5IHVzaW5nIGJvdGggYGJhc2VgIFIgYW5kLCBhbHRlcm5hdGl2ZWx5LCB0aGUgYHRpZHl2ZXJzZWAgc3ludGF4Lg0KDQojIyMgQmFzZSBSDQoNCldpdGggYGJhc2VgIFIsIHdlIHVzZSB0aGUgYGFwcGx5YCBmdW5jdGlvbiB0byBjb21wdXRlIHRoZSBjb21wb3NpdGUgc2NvcmVzIGBOVmAsIGBURGAsIGFuZCBgVENgIGJ5IGNvbXB1dGluZyB0aGUgbWVhbiBzY29yZSBieSByb3cuIFRoZW4sIHdlIHVzZSB0aGUgc2FtZSBjb2RlIHNob3duIGluIHNlY3Rpb24gMS41IHRvIGNvbXB1dGUgdGhlIGNsdXN0ZXItbWVhbiAobmFtZWQgYE5WYmAsIGBURGJgLCBhbmQgYFRDYmApIGFuZCBjbHVzdGVyLW1lYW4tY2VudGVyZWQgc2NvcmVzIChuYW1lZCBgTlZ3YCwgYFREd2AsIGFuZCBgVEN3YCkuDQpgYGB7ciAgfQ0KIyBjb21wdXRpbmcgY29tcG9zaXRlIHNjb3Jlcw0KaWxkJE5WIDwtIGFwcGx5KGlsZFssYygidjEiLCJ2MiIsInYzIildLDEsbWVhbixuYS5ybT1UUlVFKSAjIE5lZ2F0aXZlIFZhbGVuY2UNCmlsZCRURCA8LSBhcHBseShpbGRbLGMoImQxIiwiZDIiLCJkMyIsImQ0IildLDEsbWVhbixuYS5ybT1UUlVFKSAjIFRhc2sgRGVtYW5kcw0KaWxkJFRDIDwtIGFwcGx5KGlsZFssYygiYzEiLCJjMiIsImMzIildLDEsbWVhbixuYS5ybT1UUlVFKSAjIFRhc2sgQ29udHJvbA0KDQojIHNlbGVjdGluZyB2YXJpYWJsZSBuYW1lcw0KVmFyTmFtZXMgPC0gYygiTlYiLCJURCIsIlRDIikNCg0KIyBjb21wdXRpbmcgY2x1c3Rlci1tZWFuIHZhbHVlcyBvZiB0aW1lLXZhcnlpbmcgdmFyaWFibGVzIChzZWUgc2VjdGlvbiAxLjUpDQptZWFucyA8LSBhZ2dyZWdhdGUoeD1pbGRbLFZhck5hbWVzXSxieT1saXN0KGlsZCRJRCksRlVOPW1lYW4pIA0KY29sbmFtZXMobWVhbnMpIDwtIGMoIklEIixwYXN0ZTAoVmFyTmFtZXMsImIiKSkNCmlsZCA8LSBwbHlyOjpqb2luKGlsZCxtZWFucyxieT0iSUQiKQ0KDQojIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFsdWVzIChzZWUgc2VjdGlvbiAxLjUpDQpmb3IoVmFyTmFtZSBpbiBWYXJOYW1lcyl7IA0KICBpbGRbLHBhc3RlMChWYXJOYW1lLCJ3IildIDwtIGlsZFssVmFyTmFtZV0gLSBpbGRbLHBhc3RlMChWYXJOYW1lLCJiIildIH0gDQoNCiMgc2hvd2luZyBleGFtcGxlIHZhcmlhYmxlcw0KaWxkWyxjKCJJRCIsImRheSIsImJlZXAiLCJOViIsIk5WYiIsIk5WdyIpXQ0KYGBgDQoNCkhlcmUsIHdlIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgcmVzdWx0aW5nIGNvbXBvc2l0ZSBzY29yZXMuIFdlIGNhbiBzZWUgdGhhdCBjb21wb3NpdGUgc2NvcmVzIGFyZSBxdWl0ZSBzeW1tZXRyaWNhbGx5IGRpc3RyaWJ1dGVkLCBhbHRob3VnaCB3aXRoIHNvbWUgcG9zaXRpdmUgc2tld25lc3MgZm9yIG5lZ2F0aXZlIHZhbGVuY2UuIENsdXN0ZXItbWVhbi1jZW50ZXJlZCBzY29yZSBkaXN0cmlidXRpb25zIGFyZSBtb3JlIHN5bW1ldHJpYyB0aGFuIGNsdXN0ZXItbWVhbiBkaXN0cmlidXRpb25zLg0KYGBge3IgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yfQ0KIyB2aXN1YWxpemluZyBjb21wb3NpdGUgc2NvcmUgZGlzdHJpYnV0aW9ucw0KcGFyKG1mcm93PWMoMSwzKSkNCmZvcihWYXJOYW1lIGluIFZhck5hbWVzKXsgDQogIGhpc3QoaWxkWyxWYXJOYW1lXSxtYWluPVZhck5hbWUseGxhYj0iIixicmVha3M9MzApIH0NCg0KIyB2aXN1YWxpemluZyBjbHVzdGVyIG1lYW5zIG9mIGNvbXBvc2l0ZSBzY29yZXMNCmZvcihWYXJOYW1lIGluIHBhc3RlMChWYXJOYW1lcywiYiIpKXsNCiAgaGlzdChpbGRbIWR1cGxpY2F0ZWQoaWxkJElEKSxWYXJOYW1lXSxtYWluPVZhck5hbWUseGxhYj0iIixicmVha3M9MzApIH0NCg0KIyB2aXN1YWxpemluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgY29tcG9zaXRlIHNjb3Jlcw0KZm9yKFZhck5hbWUgaW4gcGFzdGUwKFZhck5hbWVzLCJ3IikpeyANCiAgaGlzdChpbGRbLFZhck5hbWVdLG1haW49VmFyTmFtZSx4bGFiPSIiLGJyZWFrcz0zMCkgfQ0KYGBgDQoNCjxicj4NCg0KIyMjIFRpZHl2ZXJzZQ0KDQpIZXJlLCB3ZSByZXBsaWNhdGUgdGhlIHNhbWUgb3BlcmF0aW9ucyBpbiB0d28gYWx0ZXJuYXRpdmUgd2F5cyBiYXNlZCBvbiB0aGUgYHRpZHl2ZXJzZWAgc3ludGF4IChzZWUgW1dpY2toYW0gZXQgYWwuLCAyMDIzXSgjcmVmKSkuIEluIG9wdGlvbiBBLCB3ZSB1c2UgdGhlIHBpcGUgb3BlcmF0b3IgYCU+JWAgdG8gY29uY2F0ZW5hdGUgb3BlcmF0aW9ucywgdGhlIGBncm91cF9ieWAgZnVuY3Rpb24gdG8gZ3JvdXAgb3BlcmF0aW9ucyBieSBwYXJ0aWNpcGFudCBgSURgLCBhbmQgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIHNwZWNpZnkgd2hpY2ggb3BlcmF0aW9ucyBzaG91bGQgYmUgYXBwbGllZCAoaS5lLiwgY29tcHV0aW5nIGNvbXBvc2l0ZSBzY29yZXMgYW5kIHRoZWlyIGNsdXN0ZXIgbWVhbnMgYW5kIGNsdXN0ZXItbWVhbi1jZW50ZXJlZCB2YWx1ZXMpLiBJbiBvcHRpb24gQiwgd2UgZGlyZWN0bHkgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBzcGVjaWZ5IGFsbCBvcGVyYXRpb25zIHRvIGJlIGFwcGxpZWQgYW5kIHRoZSBncm91cGluZyB2YXJpYWJsZSAoc3BlY2lmaWVkIHdpdGggdGhlIGFyZ3VtZW50IGAuYnlgKS4NCmBgYHtyICB9DQojIGxvYWRpbmcgdGlkeXZlcnNlIHBhY2thZ2UgY29sbGVjdGlvbg0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgb3B0aW9uIEE6IG11dGF0ZSBhbmQgZ3JvdXBfYnkNCmlsZF90aWR5dmVyc2VfQSA8LSANCiAgaWxkICU+JQ0KICBncm91cF9ieShJRCkgJT4lICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCiAgICAgICAgICMgY29tcHV0aW5nIGNvbXBvc2l0ZSBzY29yZXMNCiAgbXV0YXRlKE5WID0gbWVhbihjKHYxLHYyLHYzKSksIA0KICAgICAgICAgVEQgPSBtZWFuKGMoZDEsZDIsZDMsZDQpKSwNCiAgICAgICAgIFRDID0gbWVhbihjKGMxLGMyLGMzKSksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gdmFyaWFibGVzDQogICAgICAgICBOVl9tZWFuID0gbWVhbihOViksDQogICAgICAgICBURF9tZWFuID0gbWVhbihURCksDQogICAgICAgICBUQ19tZWFuID0gbWVhbihUQyksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGVzDQogICAgICAgICBOVl9jbWMgPSBOViAtIE5WX21lYW4sDQogICAgICAgICBURF9jbWMgPSBURCAtIFREX21lYW4sDQogICAgICAgICBUQ19jbWMgPSBUQyAtIFRDX21lYW4pIA0KaWxkX3RpZHl2ZXJzZV9BWyxjKCJJRCIsImRheSIsImJlZXAiLCJjMSIsImMxX21lYW4iLCJjMV9jbWMiLCJkMSIsImQxX21lYW4iLCJkMV9jbWMiKV0NCg0KIyBvcHRpb24gQjogbXV0YXRlIHdpdGggIi5ieSINCmlsZF90aWR5dmVyc2VfQiA8LSANCiAgbXV0YXRlKGlsZCwNCiAgICAgICAgICMgY29tcHV0aW5nIGNvbXBvc2l0ZSBzY29yZXMNCiAgICAgICAgIE5WID0gbWVhbihjKHYxLHYyLHYzKSksIA0KICAgICAgICAgVEQgPSBtZWFuKGMoZDEsZDIsZDMsZDQpKSwNCiAgICAgICAgIFRDID0gbWVhbihjKGMxLGMyLGMzKSksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4gdmFyaWFibGVzDQogICAgICAgICBOVl9tZWFuID0gbWVhbihOViksDQogICAgICAgICBURF9tZWFuID0gbWVhbihURCksDQogICAgICAgICBUQ19tZWFuID0gbWVhbihUQyksDQogICAgICAgICAjIGNvbXB1dGluZyBjbHVzdGVyLW1lYW4tY2VudGVyZWQgdmFyaWFibGVzDQogICAgICAgICBOVl9jbWMgPSBOViAtIE5WX21lYW4sDQogICAgICAgICBURF9jbWMgPSBURCAtIFREX21lYW4sDQogICAgICAgICBUQ19jbWMgPSBUQyAtIFRDX21lYW4sDQogICAgICAgICAuYnkgPSBJRCkgIyBncm91cGluZyBvcGVyYXRpb25zIGJ5IGNsdXN0ZXIgdmFyaWFibGUgIklEIg0KaWxkX3RpZHl2ZXJzZV9CWyxjKCJJRCIsImRheSIsImJlZXAiLCJjMSIsImMxX21lYW4iLCJjMV9jbWMiLCJkMSIsImQxX21lYW4iLCJkMV9jbWMiKV0NCmBgYA0KDQo8YnI+DQoNCiMjIDEuOC4gTGFnZ2luZyBhbmQgbGVhZGluZyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KSGVyZSwgd2UgcHJvdmlkZSBzb21lIGNvZGUgZXhlbXBsaWZ5aW5nIGhvdyB0byBtYW5pcHVsYXRlIElMRCBkYXRhIHRvIG1vdmUgYSB2YXJpYWJsZSAodGFzayBkZW1hbmRzKSBvbmUgdGltZSBwb2ludCBiYWNrd2FyZCAobGFnZ2luZykgb3IgZm9yd2FyZCAobGVhZGluZykgLCBhbHRob3VnaCBzdWNoIHRyYW5zZm9ybWVkIHZhcmlhYmxlcyBhcmUgbm90IHVzZWQgaW4gdGhlIGZvbGxvd2luZyBhbmFseXNlcy4gIEFzIGRvbmUgYWJvdmUsIHdlIHNob3cgaG93IHRvIGltcGxlbWVudCB0aGlzIHN0ZXAgYnkgdXNpbmcgYm90aCBgYmFzZWAgUiBhbmQsIGFsdGVybmF0aXZlbHksIHRoZSBgdGlkeXZlcnNlYCBzeW50YXguDQoNCiMjIyBCYXNlIFINCg0KV2l0aCBgYmFzZWAgUiwgbGFnZ2luZyBpcyBpbXBsZW1lbnRlZCB3aXRoIGEgZm9yLWxvb3AgdGhhdCBwYXN0ZXMgdGhlIHZhcmlhYmxlIHZhbHVlIGZyb20gdGhlIHByZXZpb3VzIHJvdyBpZiB0aGUgdmFsdWVzIG9mIGJvdGggcGFydGljaXBhbnQgKGkuZS4sIGBJRGApIGFuZCB0aW1lIGlkZW50aWZpZXJzIChpLmUuLCBgZGF5YCkgYXJlIGVxdWFsIHRvIHRob3NlIG9mIHRoZSBwcmV2aW91cyByb3cuIFNpbWlsYXJseSwgbGVhZGluZyBpcyBpbXBsZW1lbnRlZCB3aXRoIGEgZm9yLWxvb3AgdGhlIHBhc3RlcyB0aGUgdmFyaWFibGUgdmFsdWUgZnJvbSB0aGUgZm9sbG93aW5nIHJvdyBpZiB0aGUgcGFydGljaXBhbnQgYW5kIHRpbWUgdmFsdWVzIGFyZSBlcXVhbCB0byB0aG9zZSBvZiB0aGUgZm9sbG93aW5nIHJvdy4gSGVyZSwgd2Ugc2hvdyBhbiBleGFtcGxlIHdpdGggdGhlIHZhcmlhYmxlIGBURGAuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBzYXZpbmcgZGF0YSBhcyBhbiBhbHRlcm5hdGl2ZSBkYXRhc2V0DQppbGRfYmFzZVIgPC0gaWxkWyxjKCJJRCIsImRheSIsIlREIildDQoNCiMgbGFnZ2luZyBURCB2YXJpYWJsZQ0KZm9yKGkgaW4gMjpucm93KGlsZCkpeyAjIGZvciBlYWNoIHJvdyBpbiB0aGUgaWxkIGRhdGFzZXQNCiAgaWYoaWxkW2ksIklEIl0gPT0gaWxkW2ktMSwiSUQiXSAmICMgSUYgc2FtZSBJRCBvZiB0aGUgcHJldmlvdXMgcm93Li4uIA0KICAgICBpbGRbaSwiZGF5Il0gPT0gaWxkW2ktMSwiZGF5Il0peyAjIC4uLkFORCBzYW1lIGRheSBvZiB0aGUgcHJldmlvdXMgcm93Li4uDQogICAgaWxkX2Jhc2VSW2ksIlRELmxhZyJdIDwtIGlsZFtpLTEsIlREIl0gIyAuLi5wYXN0ZSB0aGUgdmFsdWUgb2YgdGhlIHByZXZpb3VzIHJvdw0KICB9fQ0KDQojIGxlYWRpbmcgVEQgdmFyaWFibGUNCmZvcihpIGluIDE6KG5yb3coaWxkKS0xKSl7ICMgZm9yIGVhY2ggcm93IGluIHRoZSBpbGQgZGF0YXNldA0KICBpZihpbGRbaSwiSUQiXSA9PSBpbGRbaSsxLCJJRCJdICYgIyBJRiBzYW1lIElEIG9mIHRoZSBuZXh0IHJvdy4uLiANCiAgICAgaWxkW2ksImRheSJdID09IGlsZFtpKzEsImRheSJdKXsgIyAuLi5BTkQgc2FtZSBkYXkgb2YgdGhlIG5leHQgcm93Li4uDQogICAgaWxkX2Jhc2VSW2ksIlRELmxlYWQiXSA8LSBpbGRbaSsxLCJURCJdICMgLi4ucGFzdGUgdGhlIHZhbHVlIG9mIHRoZSBuZXh0IHJvdw0KICB9fQ0KDQojIHNob3dpbmcgb3JpZ2luYWwsIGxhZ2dlZCwgYW5kIGxlZCB2YXJpYWJsZQ0KaWxkX2Jhc2VSWyxjKCJJRCIsImRheSIsIlREIiwiVEQubGFnIiwiVEQubGVhZCIpXQ0KYGBgDQoNCjxicj4NCg0KIyMjIFRpZHl2ZXJzZQ0KDQpIZXJlLCB3ZSByZXBsaWNhdGUgdGhlIHNhbWUgb3BlcmF0aW9ucyBpbiB0aHJlZSBhbHRlcm5hdGl2ZSB3YXlzIGJhc2VkIG9uIHRoZSBgdGlkeXZlcnNlYCBzeW50YXggKHNlZSBbV2lja2hhbSBldCBhbC4sIDIwMjNdKCNyZWYpKSwgYWxsIG9mIHdoaWNoIHVzZXMgdGhlIGBsYWdgIGFuZCB0aGUgYGxlYWRgLCBmdW5jdGlvbnMgd2l0aGluIHRoZSBgbXV0YXRlYCBmdW5jdGlvbi4gSW4gb3B0aW9uIEEsIEluIG9wdGlvbiBBLCB3ZSB1c2UgdGhlIHBpcGUgb3BlcmF0b3IgYCU+JWAgdG8gY29uY2F0ZW5hdGUgb3BlcmF0aW9ucywgdGhlIGBncm91cF9ieWAgZnVuY3Rpb24gdG8gZ3JvdXAgb3BlcmF0aW9ucyBieSBwYXJ0aWNpcGFudCBgSURgIGFuZCBgZGF5YCwgYW5kIHRoZSBgbXV0YXRlYCwgYGxhZ2AsIGFuZCBgbGVhZGAgZnVuY3Rpb25zIHRvIHNwZWNpZnkgd2hpY2ggb3BlcmF0aW9ucyBzaG91bGQgYmUgYXBwbGllZCAoaS5lLiwgbGFnZ2luZyBhbmQgbGVhZGluZyBieSAqbiogPSAxIHdpdGhpbiB0aGUgc2FtZSBkYXkgYW5kIHRoZSBwYXJ0aWNpcGFudCkuIEluIG9wdGlvbiBCLCB3ZSBkaXJlY3RseSB1c2UgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIHNwZWNpZnkgYm90aCB0aGUgb3BlcmF0aW9ucyB0byBiZSBhcHBsaWVkIGFuZCB0aGUgdHdvIGdyb3VwaW5nIHZhcmlhYmxlcyAoc3BlY2lmaWVkIHdpdGggdGhlIGFyZ3VtZW50IGAuYnlgKS4gRmluYWxseSwgb3B0aW9uIEMgaXMgYW4gZXh0ZW5zaW9uIG9mIG9wdGlvbiBCIHdoZXJlIHdlIHVzZSB0aGUgYGFjcm9zc2AgZnVuY3Rpb24gdG8gcmVwZWF0IHRoZSBvcGVyYXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYC5mbnNgIGFyZ3VtZW50IGFjcm9zcyBhbGwgdGhlIGNvbHVtbnMgc3BlY2lmaWVkIGluIHRoZSBgLmNvbHNgIGFyZ3VtZW50IG9mIHRoZSBgbXV0YXRlYCBmdW5jdGlvbi4gSW4gdGhpcyB3YXksIGl0IGlzIHBvc3NpYmxlIHRvIGF2b2lkIG1hbnVhbGx5IHJld3JpdGluZyB0aGUgc2FtZSBvcGVyYXRpb25zIGZvciBlYWNoIHZhcmlhYmxlLCBhcyBpbiBvcHRpb24gQSBhbmQgQi4gDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBsb2FkaW5nIHRpZHl2ZXJzZSBwYWNrYWdlIGNvbGxlY3Rpb24NCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojIG9wdGlvbiBBOiBtdXRhdGUgYW5kIGdyb3VwX2J5DQppbGRfdGlkeXZlcnNlX0EgPC0gDQogIGlsZCAlPiUNCiAgZ3JvdXBfYnkoSUQsZGF5KSAlPiUgIyBncm91cGluZyBvcGVyYXRpb25zIGJ5IGNsdXN0ZXIgdmFyaWFibGUgIklEIg0KICBtdXRhdGUoVEQubGFnID0gbGFnKFRELCBuID0gMSksICMgbGFnZ2luZyB0aGUgVEQgdmFyaWFibGUNCiAgICAgICAgIFRELmxlYWQgPSBsZWFkKFRELCBuID0gMSkpICMgbGVhZGluZyB0aGUgVEQgdmFyaWFibGVyaWFibGUNCmlsZF90aWR5dmVyc2VfQVssYygiSUQiLCJkYXkiLCJURCIsIlRELmxhZyIsIlRELmxlYWQiKV0gIyBzaG93aW5nIGRhdGENCg0KIyBvcHRpb24gQjogbXV0YXRlIHdpdGggIi5ieSINCmlsZF90aWR5dmVyc2VfQiA8LSANCiAgbXV0YXRlKGlsZCwNCiAgICAgICAgIFRELmxhZyA9IGxhZyhURCwgbiA9IDEpLCAjIGxhZ2dpbmcgdGhlIFREIHZhcmlhYmxlDQogICAgICAgICBURC5sZWFkID0gbGVhZChURCwgbiA9IDEpLCAjIGxlYWRpbmcgdGhlIFREIHZhcmlhYmxlDQogICAgICAgICAuYnkgPSBjKElELGRheSkpICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCmlsZF90aWR5dmVyc2VfQlssYygiSUQiLCJkYXkiLCJURCIsIlRELmxhZyIsIlRELmxlYWQiKV0gIyBzaG93aW5nIGRhdGENCg0KIyBvcHRpb24gQzogcmVwZWF0IG9wdGlvbiBCIG92ZXIgbXVsdGlwbGUgY29sdW1ucyB1c2luZyB0aGUgImFjcm9zcyIgY29tbWFuZA0KaWxkX3RpZHl2ZXJzZV9DIDwtDQogIG11dGF0ZShpbGQsDQogICAgICAgICBhY3Jvc3MoDQogICAgICAgICAgICMgc2VsZWN0aW5nIGFsbCB0aGUgY29sdW1ucyBvbiB3aGljaCByZXBlYXRpbmcgdGhlIG9wZXJhdGlvbnMNCiAgICAgICAgICAgLmNvbHMgPSBjKCJURCIsIlRDIiwiTlYiKSwgDQogICAgICAgICAgIC5mbnMgPSBsaXN0KCAjIGxpc3Qgb2Ygb3BlcmF0aW9ucyB0byBiZSByZXBlYXRlZA0KICAgICAgICAgICAgIGxhZyA9fiBsYWcoLngsIG4gPSAxKSwgIyBsYWdnaW5nIHRoZSBURCB2YXJpYWJsZQ0KICAgICAgICAgICAgIGxlYWQgPX4gbGVhZCgueCwgbiA9IDEpICkpLCAjIGxlYWRpbmcgdGhlIFREIHZhcmlhYmxlDQogICAgICAgICAuYnkgPSBjKElELGRheSkpICMgZ3JvdXBpbmcgb3BlcmF0aW9ucyBieSBjbHVzdGVyIHZhcmlhYmxlICJJRCINCmlsZF90aWR5dmVyc2VfQ1ssYygiSUQiLCJkYXkiLCJURCIsIlREX2xhZyIsIlREX2xlYWQiLCJUQyIsIlRDX2xhZyIsIlRDX2xlYWQiKV0gIyBzaG93aW5nIGRhdGENCmBgYA0KDQo8YnI+DQoNCiMgMi4gRGF0YSBhbmFseXNpcyB7I2FuYWx5c2VzfQ0KDQojIyAyLjEuIERlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCkhlcmUsIHdlIGNvbXB1dGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcywgbmFtZWx5IHRoZSBudW1iZXIgb2YgaW5jbHVkZWQgb2JzZXJ2YXRpb25zIGFuZCBwYXJ0aWNpcGFudHMsIG1lYW4sIFNELCBhbmQgZnJlcXVlbmNpZXMgb2YgZWFjaCBpbmNsdWRlZCB2YXJpYWJsZXMsIHRoZSBJQ0MoMSkgb2YgdGltZS12YXJ5aW5nIHZhcmlhYmxlcywgYW5kIHRoZSBsZXZlbC1zcGVjaWZpYyBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGluY2x1ZGVkIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuIFRvIGlsbHVzdHJhdGUgaG93IHRoZSBzYW1lIG91dHB1dCBjYW4gYmUgb2J0YWluZWQgaW4gbXVsdGlwbGUgd2F5cywgd2UgY29tcHV0ZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGJvdGggdXNpbmcgYGJhc2VgIFIgc3ludGF4IGFuZCwgYWx0ZXJuYXRpdmVseSwgdXNpbmcgdGhlIGBwc3ljaGAgcGFja2FnZS4NCg0KIyMjIEJhc2UgUg0KDQpXaXRoIGBiYXNlYCBSLCB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgYW5kIHRoZSBmcmVxdWVuY3kgb2YgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFyZSBjb21wdXRlZCB3aXRoaW4gYSBmb3ItbG9vcC4gQSBzZWNvbmQgZm9yLWxvb3AgaXMgdGhlbiB1c2VkIHRvIGV4dHJhY3QgdGhlIHZhcmlhbmNlIGNvbXBvbmVudHMgZnJvbSBpbnRlcmNlcHQtb25seSBsaW5lYXIgbWl4ZWQtZWZmZWN0cyByZWdyZXNzaW9uIG1vZGVscywgd2hpY2ggYXJlIHVzZWQgdG8gZXN0aW1hdGUgdGhlIElDQygxKS4gRmluYWxseSwgd2UgdXNlIHRoZSBgY29yYCBmdW5jdGlvbiB0byBjb21wdXRlIGFuZCBtZXJnZSB3aXRoaW4tIGFuZCBiZXR3ZWVuLWluZGl2aWR1YWwgY29ycmVsYXRpb25zLg0KDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIG51bWJlciBvZiBpbmNsdWRlZCBvYnNlcnZhdGlvbnMNCmNhdCgiTGV2ZWwgMToiLG5yb3coaWxkKSwib2JzZXJ2YXRpb25zOyBMZXZlbCAyOiIsbnJvdyhpbGRbIWR1cGxpY2F0ZWQoaWxkJElEKSxdKSwicGFydGljaXBhbnRzIikNCg0KIyBzZWxlY3RpbmcgdmFyaWFibGUgbmFtZXMNClZhck5hbWVzIDwtIGMoIk5WIiwiVEQiLCJUQyIpDQoNCiMgY29tcHV0aW5nIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbg0KZGVzYyA8LSBjKCkgIyBlbXB0eSB2ZWN0b3IgdG8gYmUgZmlsbGVkIHdpdGggZGVzY3JpcHRpdmUgc3RhdHMNCmZvcihWYXJOYW1lIGluIFZhck5hbWVzKXsgIyBmb3IgZWFjaCB0aW1lLXZhcnlpbmcgdmFyaWFibGUuLi4NCiAgZGVzY1tWYXJOYW1lXSA8LSAjIC4uLmNvbXB1dGluZyBtZWFuIGFuZCBTRCBhbmQgcGFzdGluZyB0aGVtIHRvZ2V0aGVyDQogICAgcGFzdGUwKHJvdW5kKG1lYW4oaWxkWyxWYXJOYW1lXSksMiksDQogICAgICAgICAgICIgKCIscm91bmQoc2QoaWxkWyxWYXJOYW1lXSksMiksIikiKSB9IA0KZGVzY1siYWdlIl0gPC0gIyBzYW1lIHRoaW5nIGZvciBhZ2UgYnV0IGJhc2VkIG9uIHRoZSB3aWRlLWZvcm0gZGF0YXNldA0KICBwYXN0ZTAocm91bmQobWVhbihwcmVscXMkYWdlKSwyKSwgDQogICAgICAgICAiICgiLHJvdW5kKHNkKHByZWxxcyRhZ2UpLDIpLCIpIikgDQpkZXNjWyJnZW5kZXIiXSA8LSAjIGZyZXF1ZW5jeSBhbmQgJSBvZiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgKGdlbmRlcikNCiAgcGFzdGUwKHRhYmxlKHByZWxxcyRnZW5kZXIpWzFdLCIgRiAoIiwNCiAgICAgICAgIHJvdW5kKDEwMCpwcm9wLnRhYmxlKHRhYmxlKHByZWxxcyRnZW5kZXIpKSwyKSwiJSkiKQ0KDQojIGNvbXB1dGluZyBJQ0MoMSkgYmFzZWQgb24gdmFyaWFuY2UgZGVjb21wb3NpdGlvbg0KbGlicmFyeShsbWU0KSAjIGxvYWRpbmcgcGFja2FnZSB0byBmaXQgbGluZWFyIG1peGVkLWVmZmVjdHMgcmVncmVzc2lvbiBtb2RlbHMNCmljYyA8LSBjKCkgIyBlbXB0eSB2ZWN0b3IgdG8gYmUgZmlsbGVkIHdpdGggSUNDIHZhbHVlcw0KZm9yKFZhck5hbWUgaW4gVmFyTmFtZXMpeyAjIGZvcmVhY2ggdGltZS12YXJ5aW5nIHZhcmlhYmxlLi4NCiAgZml0IDwtIGxtZXIoYXMuZm9ybXVsYShwYXN0ZShWYXJOYW1lLCJ+ICgxfElEKSIpKSwgZGF0YSA9IGlsZCkgIyBmaXR0aW5nIG51bGwgbXVsdGlsZXZlbCBtb2RlbA0KICB0YXUwMCA8LSBzdW1tYXJ5KGZpdCkkdmFyY29yJElEW1sxXV0gIyB2YXJpYW5jZSBvZiB0aGUgcmFuZG9tIGludGVyY2VwdA0KICBzaWdtYTIgPC0gc3VtbWFyeShmaXQpJHNpZ21hXjIgIyByZXNpZHVhbCB2YXJpYW5jZQ0KICBpY2MgPC0gYyhpY2MsIFZhck5hbWUgPSByb3VuZCh0YXUwMC8odGF1MDAgKyBzaWdtYTIpLDIpKSAjIElDQyA9IHRhdTAwLyh0YXUwMCtzaWdtYTIpDQogIH0NCg0KIyBjb21wdXRpbmcgbGV2ZWwtc3BlY2lmaWMgY29ycmVsYXRpb25zIGFtb25nIHRpbWUtdmFyeWluZyB2YXJpYWJsZXMNCmNvcjEgPC0gcm91bmQoY29yKGlsZFsscGFzdGUwKFZhck5hbWVzLCJ3IildKSwyKSAjIGxldmVsIDEgKGNsdXN0ZXItbWVhbi1jZW50ZXJlZCkNCmNvcjIgPC0gcm91bmQoY29yKGlsZFshZHVwbGljYXRlZChpbGQkSUQpLHBhc3RlMChWYXJOYW1lcywiYiIpXSksMikgIyBsZXZlbCAyIChjbHVzdGVyIG1lYW5zKQ0KY29yMVtsb3dlci50cmkoY29yMSldIDwtIGNvcjJbbG93ZXIudHJpKGNvcjIpXSAjIG1lcmdpbmcgdGhlIHR3byBtYXRyaWNlcw0Kcm93bmFtZXMoY29yMSkgPC0gY29sbmFtZXMoY29yMSkgPC0gVmFyTmFtZXMgIyBhZGRpbmcgdmFyaWFibGUgbGFiZWxzDQoNCiMgYWRkaW5nIGxldmVsLTIgY29ycmVsYXRpb25zIHdpdGggYWdlICsgZW1wdHkgcm93IGZvciBnZW5kZXINCmNvcjEgPC0gcmJpbmQoY29yMSwNCiAgICAgICAgICAgICAgY29yKHg9aWxkWyFkdXBsaWNhdGVkKGlsZCRJRCksYyhwYXN0ZTAoVmFyTmFtZXMsImIiKSwiYWdlIildLClbNCwxOjNdLA0KICAgICAgICAgICAgICBtYXRyaXgocmVwKE5BLDMpLG5yb3c9MSkpDQpyb3duYW1lcyhjb3IxKVs0OjVdIDwtIGMoImFnZSIsImdlbmRlciIpDQoNCiMgam9pbmluZyBhbmQgcHJpbnRpbmcgZGVzY3JpcHRpdmUgc3RhdHMsIElDQywgYW5kIGNvcnJlbGF0aW9ucw0KY2JpbmQoZGF0YS5mcmFtZShEZXNjID0gZGVzYywgSUNDID0gYyhpY2MsIE5BLCBOQSkpLCByb3VuZChjb3IxLCAyKSkNCmBgYA0KDQo8YnI+DQoNCiMjIyBwc3ljaA0KDQpIZXJlLCB3ZSBpbGx1c3RyYXRlIGhvdyB0aGUgc2FtZSBvcGVyYXRpb25zIGNhbiBiZSBvcHRpbWl6ZWQgd2l0aCB0aGUgYHBzeWNoYCBwYWNrYWdlLiBGaXJzdCwgd2UgdXNlIHRoZSBgZGVzY3JpYmVgIGZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMsIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBlYWNoIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4gU2Vjb25kLCB3ZSB1c2UgdGhlIGBzdGF0QnlgIGZ1bmN0aW9uIHRvIGNvbXB1dGUgSUNDcygxKSBmb3IgZWFjaCB0aW1lLXZhcnlpbmcgdmFyaWFibGUgYW5kIGxldmVsLXNwZWNpZmljIGNvcnJlbGF0aW9ucy4gRmluYWxseSwgd2Ugc2hvdyBob3cgdG8gZXh0cmFjdCBhbmQgcmVwb3J0IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgZWFjaCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudC4NCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQojIGxvYWRpbmcgcHN5Y2ggcGFja2FnZQ0KbGlicmFyeShwc3ljaCkNCg0KIyBjb21wdXRpbmcgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgbWVhbiBhbmQgc2QNCmRlc2MgPC0gcmJpbmQoZGVzY3JpYmUoaWxkWyxjKCJOViIsIlREIiwiVEMiKV0pWyxjKCJuIiwibWVhbiIsInNkIildLCAjIHRpbWUtdmFyeWluZw0KICAgICAgICAgICAgICBkZXNjcmliZShwcmVscXNbLCJhZ2UiXSlbLGMoIm4iLCJtZWFuIiwic2QiKV0pICMgdGltZS1pbnZhcmlhbnQNCg0KIyBjb21wdXRpbmcgSUNDKDEpDQppY2MgPC0gYyhyb3VuZChzdGF0c0J5KGlsZFssYygiTlYiLCJURCIsIlRDIildLGdyb3VwPWlsZCRJRCkkSUNDMVsxOjNdLDIpKSANCg0KIyBjb21wdXRpbmcgbGV2ZWwtc3BlY2lmaWMgY29ycmVsYXRpb25zDQpjb3JzIDwtIHBzeWNoOjpzdGF0c0J5KGlsZFssYygiTlYiLCJURCIsIlRDIiwiYWdlIildLGdyb3VwPWlsZCRJRCkNCmNvcnMkcndnW2xvd2VyLnRyaShjb3JzJHJ3ZyldIDwtIGNvcnMkcmJnW2xvd2VyLnRyaShjb3JzJHJiZyldICMgbWVyZ2luZyBsdi0xICYgbHYtMiBjb3JyZWxhdGlvbnMNCg0KIyBqb2luaW5nIGFuZCBwcmludGluZyBkZXNjcmlwdGl2ZSBzdGF0cywgSUNDLCBhbmQgY29ycmVsYXRpb25zDQpkZXNjIDwtIGNiaW5kKGRhdGEuZnJhbWUoRGVzYyA9IGRlc2MsIElDQyA9IGMoaWNjLCBOQSkpLCByb3VuZChjb3JzJHJ3Z1ssMTozXSwgMikpDQpyb3duYW1lcyhkZXNjKSA8LSBjKCJOViIsIlREIiwiVEMiLCJhZ2UiKSAjIHJlbmFtaW5nIHJvd3MNCmNvbG5hbWVzKGRlc2MpIDwtIGMoIm4iLCJtZWFuIiwiU0QiLCJJQ0MiLCJOViIsIlREIiwiVEMiKSAjIHJlbmFtaW5nIGNvbHVtbnMNCmRlc2MgIyBwcmludGluZyBkZXNjcmlwdGl2ZSBzdGF0cw0KDQojIG9wdGlvbmFsOiBhZGRpbmcgYXN0ZXJpc2tzIGZvciBwLXZhbHVlcw0KY29ycyRwd2dbbG93ZXIudHJpKGNvcnMkcHdnKV0gPC0gY29ycyRwYmdbbG93ZXIudHJpKGNvcnMkcGJnKV0gIyBtZXJnaW5nIGx2LTEgJiBsdi0yIHAtdmFsdWVzDQpwIDwtIG1hdHJpeChucm93PTQsbmNvbD0zKSAjIGNyZWF0aW5nIGVtcHR5IG1hdHJpeCB0byBiZSBmaWxsZWQgd2l0aCBzaWduaWZpY2FuY2UgbGV2ZWxzDQpmb3IoaSBpbiAxOjQpew0KICBmb3IoaiBpbiAxOjMpew0KICAgIGlmKCFpcy5uYShjb3JzJHB3Z1tpLGpdKSAmIGNvcnMkcHdnW2ksal0gIT0gMSl7DQogICAgICBkZXNjW2ksais0XSA8LSBwYXN0ZTAoZGVzY1tpLGorNF0sICMgYWRkaW5nIGFzdGVyaXNrcyB0byBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29ycyRwd2dbaSxqXSA8IC4wMDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqKioiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29ycyRwd2dbaSxqXSA8IC4wMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqKiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29ycyRwd2dbaSxqXSA8IC4wNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKiIsIiIpKSkpIH19fQ0KZGVzYyAjIHByaW50aW5nIGRlc2NyaXB0aXZlIHN0YXRzDQpgYGANCg0KPGJyPg0KDQojIyAyLjIuIFJlZ3Jlc3Npb24gbW9kZWxzDQoNCkhlcmUsIHdlIGZpdCBhbmQgcHJpbnQgdGhlIHR3byBpbGx1c3RyYXRpdmUgbW9kZWxzIHRlc3RpbmcgSkRDIGh5cG90aGVzZXMuIFRoaXMgaXMgZG9uZSBieSBpbmNsdWRpbmcgY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHRhc2sgZGVtYW5kcyBgVER3YCBhbmQgdGFzayBjb250cm9sIGBUQ3dgIGFuZCB0aGVpciBsZXZlbC0xIGludGVyYWN0aW9uIGluIE1vZGVsIDEsIHdoZXJlYXMgbW9kZWwgMiBpbmNsdWRlcyBhbmQgdGVzdHMgdGhlIGNyb3NzLWxldmVsIGludGVyYWN0aW9uIGJldHdlZW4gY2x1c3Rlci1tZWFuLWNlbnRlcmVkIHRhc2sgZGVtYW5kcyBgVER3YCBhbmQgdGhlIGNsdXN0ZXIgbWVhbnMgb2YgdGFzayBjb250cm9sIGBUQ2JgLiBJbiBib3RoIG1vZGVscywgd2UgaW5jbHVkZSBgYWdlYCBhbmQgYGdlbmRlcmAgYXMgbGV2ZWwtMiBjb3ZhcmlhdGVzIGFuZCBhIHJhbmRvbSBzbG9wZSBmb3IgdGFzayBkZW1hbmRzLiBCb3RoIG1vZGVscyBhcmUgZml0dGVkIHdpdGggdGhlIFJFTUwgZXN0aW1hdG9yIChzZWUgW01jTmVpc2gsIDIwMTddKCNyZWYpKS4NCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCiMgbG9hZGluZyByZXF1aXJlZCBwYWNrYWdlcw0KbGlicmFyeShsbWU0KTsgbGlicmFyeShzalBsb3QpDQpgYGANCmBgYHtyIGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9M30NCiMgZml0dGluZyBtb2RlbHMNCmZpdDEgPC0gbG1lcihOViB+IFREdyAqIFRDdyArIGFnZSArIGdlbmRlciArIChURHd8SUQpLCBkYXRhID0gaWxkKQ0KZml0MiA8LSBsbWVyKE5WIH4gVER3ICogVENiICsgYWdlICsgZ2VuZGVyICsgKFREd3xJRCksIGRhdGEgPSBpbGQpDQoNCiMgcHJpbnRpbmcgb3V0cHV0IHRhYmxlDQp0YWJfbW9kZWwoZml0MSwgZml0MiwNCiAgICAgICAgICBzaG93LnNlID0gVFJVRSwgY29sbGFwc2Uuc2UgPSBUUlVFLCBwLnZhbCA9ICJ3YWxkIiwgIyBXYWxkIGFwcHJveGltYXRpb24NCiAgICAgICAgICBzaG93LmNpID0gRkFMU0UsIHNob3cuaWNjID0gRkFMU0UpDQpgYGANCg0KTm90ZSB0aGF0IHRoZSBtYXJnaW5hbCBhbmQgY29uZGl0aW9uYWwgJFJeMiQgYXJlIGVzdGltYXRlcyBvZiB0aGUgcHJvcG9ydGlvbiBvZiBuZWdhdGl2ZSB2YWxlbmNlIHZhcmlhbmNlIGV4cGxhaW5lZCBieSBmaXhlZCBlZmZlY3RzIG9ubHkgYW5kIGJ5IGJvdGggZml4ZWQgYW5kIHJhbmRvbSBlZmZlY3RzLCByZXNwZWN0aXZlbHkuDQoNCjxicj4NCg0KRmluYWxseSwgd2UgcGxvdCB0aGUgZXN0aW1hdGVkIGludGVyYWN0aW9ucy4NCmBgYHtyIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCiMgbG9hZGluZyByZXF1aXJlZCBwYWNrYWdlcw0KbGlicmFyeShnZ3Bsb3QyKTsgbGlicmFyeShncmlkRXh0cmEpDQpgYGANCmBgYHtyIGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9MyxtZXNzYWdlPUZBTFNFfQ0KIyBzZXR0aW5nIGdyYXBoaWNhbCBwYXJhbWV0ZXJzDQpzZF90YzEgPC0gcm91bmQoc2QoaWxkJFRDdyksMikgIyBjb21wdXRpbmcgVEMgc3RhbmRhcmQgZGV2LiBhdCBsZXZlbCAxDQptZWFuX3RjMiA8LSByb3VuZChtZWFuKG1lYW5zJFRDYiksMikgIyBjb21wdXRpbmcgbWVhbiBUQyBhdCBsZXZlbCAyDQpzZF90YzIgPC0gcm91bmQoc2QobWVhbnMkVENiKSwyKSAjIGNvbXB1dGluZyBUQyBzdGFuZGFyZCBkZXYuIGF0IGxldmVsIDINCmxhYnMgPC0gYygiLTEgU0QiLCIrMSBTRCIpICMgc2V0dGluZyBsZWdlbmQgbGFiZWxzDQpjb2xzIDwtIGMoImJsYWNrIiwiIzY2NjY2NiIpICMgc2V0dGluZyBjb2xvcnMNCmxpbnMgPC0gYygic29saWQiLCJkYXNoZWQiKSAjIHNldHRpbmcgbGluZSB0eXBlcw0KDQojIHBsb3R0aW5nDQpwIDwtIGdyaWQuYXJyYW5nZSgNCiAgIyBNb2RlbCAxIChUQ3cgKy8tIDEgU0QpDQogIHBsb3RfbW9kZWwoZml0MSx0eXBlPSJwcmVkIix0ZXJtcz1jKCJURHciLHBhc3RlMCgiVEN3IFsiLC1zZF90YzEsIiwiLHNkX3RjMSwiXSIpKSkgKyANCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobGFiZWxzPWxhYnMsdmFsdWVzPWNvbHMpICsNCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwobGFiZWxzPWxhYnMsdmFsdWVzPWxpbnMpICsgDQogICAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzPWxhYnMsdmFsdWVzPWNvbHMpICsgZ2d0aXRsZSgiIikgKyANCiAgICB4bGFiKCJUYXNrIGRlbWFuZCAod2l0aGluKSIpICsgeWxhYigiTmVnYXRpdmUgdmFsZW5jZSIpICsNCiAgICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKHRpdGxlPSJUYXNrIENvbnRyb2xcbih3aXRoaW4pIikpLA0KICAjIE1vZGVsIDIgKE1lYW4gVENiICsvLSAxIFNEKQ0KICBwbG90X21vZGVsKGZpdDIsdHlwZT0icHJlZCIsDQogICAgICAgICAgICAgdGVybXM9YygiVER3IixwYXN0ZTAoIlRDYiBbIixtZWFuX3RjMi1zZF90YzEsIiwiLG1lYW5fdGMyK3NkX3RjMSwiXSIpKSkgKw0KICAgIHNjYWxlX2NvbG9yX21hbnVhbChsYWJlbHM9bGFicyx2YWx1ZXM9Y29scykgKw0KICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbChsYWJlbHM9bGFicyx2YWx1ZXM9bGlucykgKyANCiAgICBzY2FsZV9maWxsX21hbnVhbChsYWJlbHM9bGFicyx2YWx1ZXM9Y29scykgKyBnZ3RpdGxlKCIiKSArIA0KICAgIHhsYWIoIlRhc2sgZGVtYW5kICh3aXRoaW4pIikgKyB5bGFiKCJOZWdhdGl2ZSB2YWxlbmNlIikgKw0KICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQodGl0bGU9IlRhc2sgY29udHJvbFxuKGJldHdlZW4pIikpLCBucm93PTEpDQoNCiMgZXhwb3J0aW5nIGZpZ3VyZQ0KZ2dzYXZlKCJmaWcyLnBuZyIsIHBsb3QgPSBwLCBkcGkgPSAzMDApDQpgYGANCg0KPGJyPg0KDQojIDMuIE11bHRpdmVyc2UgYXBwcm9hY2gNCg0KSGVyZSwgd2UgaW50ZWdyYXRlIHRoZSBjb2RlIHByb3ZpZGVkIGZvciBlYWNoIHN0ZXAgaW50byBhIHVuaWZpZWQgZnVuY3Rpb24gYGlsZC5tYW5pcGAgdG8gaWxsdXN0cmF0ZSBob3cgcmVzdWx0cyBtaWdodCBjaGFuZ2UgYmFzZWQgb24gZGF0YSBtYW5pcHVsYXRpb24gY2hvaWNlcy4gTm90ZSB0aGF0IHNvbWUgb2YgdGhlIGZ1bmN0aW9uIGFyZ3VtZW50cyBhcmUgc2V0IGJ5IGRlZmF1bHQgYXMgcmVxdWlyZWQgYnkgb3VyIGlsbHVzdHJhdGl2ZSBleGFtcGxlLg0KDQo8ZGV0YWlscz48c3VtbWFyeT5zaG93IGBpbGQubWFuaXBgPC9zdW1tYXJ5Pg0KPHA+DQpgYGB7ciB9DQojJyBAdGl0bGUgSW50ZW5zaXZlIGxvbmdpdHVkaW5hbCBkYXRhIG1hbmlwdWxhdGlvbg0KIycgQHBhcmFtIGxvbmcgPSBsb25nLWZvcm0gZGF0YXNldCAoZGF0YS5mcmFtZSkNCiMnIEBwYXJhbSB3aWRlID0gd2lkZS1mb3JtIGRhdGFzZXQgKGRhdGEuZnJhbWUpDQojJyBAcGFyYW0gY2x1c3RlciA9IG5hbWUgb2YgdGhlIGNsdXN0ZXIgdmFyaWFibGUgaWRlbnRpZnlpbmcgcGFydGljaXBhbnRzIChjaGFyYWN0ZXIpDQojJyBAcGFyYW0gbG9uZy5yZXNwVGltZSA9IG5hbWUgb2YgdGhlIHRpbWUgdmFyaWFibGUgaW4gdGhlIGxvbmctZm9ybSBkYXRhc2V0IChjaGFyYWN0ZXIpDQojJyBAcGFyYW0gcmVzcFRpbWUuZm9ybWF0ID0gdGltZSBmb3JtYXQgdXNlZCBieSB0aGUgbG9uZy5yZXNwVGltZSB2YXJpYWJsZSAoY2hhcmFjdGVyKSAoc2VlID9zdHJwdGltZSkNCiMnIEBwYXJhbSBzY2hlZHVsZWRUaW1lcyA9IGxpc3Qgb2YgdGhyZWUtZWxlbWVudCBjaGFyYWN0ZXIgdmVjdG9ycyByZXBvcnRpbmcgdGhlIG1pbmltdW0sIGNlbnRyYWwsIGFuZCBtYXhpbXVtIHRpbWUgZm9yIGVhY2ggc2NoZWR1bGVkIG1lYXN1cmVtZW50IHVzaW5nIHRoZSBzYW1lIHRpbWUgZm9ybWF0IHNldCBpbiB0aGUgc2NoZWR1bGVkVGltZXMuZm9ybWF0IGFyZ3VtZW50DQojJyBAcGFyYW0gc2NoZWR1bGVkVGltZXMuZm9ybWF0ID0gdGltZSBmb3JtYXQgKHdpdGhvdXQgZGF0ZSkgdXNlZCBpbiB0aGUgc2NoZWR1bGVkVGltZXMgYXJndW1lbnQgKGNoYXJhY3RlcikgKGRlZmF1bHQgIiVIOiVNOiVTIikNCiMnIEBwYXJhbSBsb25nLnZhcmlhYmxlcyA9IGxpc3Qgb2YgdmFyaWFibGUgbmFtZXMgaW4gdGhlIGxvbmctZm9ybSBkYXRhc2V0IChpLmUuLCBmb3IgZWFjaCB2YXJpYWJsZSwgaXQgc2hvdWxkIGluY2x1ZGUgYSBsaXN0IGVsZW1lbnQgbmFtZWQgd2l0aCB0aGUgdmFyaWFibGUgbmFtZSBhbmQgaW5jbHVkaW5nIGEgdmVjdG9yIG9mIHZhcmlhYmxlIG5hbWVzIHJlcG9ydGluZyB0aGUgbmFtZSBvZiBlYWNoIGl0ZW07IHdpdGggc2luZ2xlLWl0ZW0gbWVhc3VyZXMgb25seSB0aGUgdmFyaWFibGUgbmFtZSBzaG91bGQgYmUgc3BlY2lmaWVkLCB3aXRob3V0IGFueSB2ZWN0b3IpDQojJyBAcGFyYW0gd2lkZS52YXJpYWJsZXMgPSBsaXN0IG9mIHZhcmlhYmxlIG5hbWVzIGluIHRoZSB3aWRlLWZvcm0gZGF0YXNldCAoc2VlIGxvbmcudmFyaWFibGVzKQ0KIycgQHBhcmFtIHJlbW92ZS5maXJzdC5iZWVwID0gbG9naWNhbCB2YWx1ZSBkZXRlcm1pbmluZyB3aGV0aGVyIHRoZSBmaXJzdCBtZWFzdXJlbWVudCBvY2Nhc2lvbiB3aXRoaW4gZWFjaCBkYXkgc2hvdWxkIGJlIGV4Y2x1ZGVkIChUUlVFKSBvciBub3QgKEZBTFNFLCBkZWZhdWx0KQ0KIycgQHBhcmFtIHJlbW92ZS5maXJzdC5kYXkgPSBsb2dpY2FsIHZhbHVlIGRldGVybWluaW5nIHdoZXRoZXIgdGhlIGZpcnN0IGRheSBvZiBlYWNoIHBhcnRpY2lwYW50IHNob3VsZCBiZSBleGNsdWRlZCAoVFJVRSkgb3Igbm90IChGQUxTRSwgZGVmYXVsdCkNCiMnIEBwYXJhbSBsaXN0d2lzZS5kZWwgPSBsb2dpY2FsIHZhbHVlIGRldGVybWluaW5nIHdoZXRoZXIgYSBsaXN0LXdpc2UgZGVsZXRpb24gc2hvdWxkIGJlIGFwcGxpZWQgKFRSVUUpIG9yIG5vdCAoRkFMU0UsIGRlZmF1bHQpDQojJyBAcGFyYW0gY29tcGxpYW5jZS5jdXRvZmYgPSBudW1lcmljIHZhbHVlIGluZGV4aW5nIHRoZSBtaW5pbXVtIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgb3IgY29tcGxpYW5jZSByYXRlIGN1dC1vZmYgdXNlZCB0byBleGNsdWRlIHBhcnRpY2lwYW50cyAoTkEgYnkgZGVmYXVsdCwgbWVhbmluZyB0aGF0IGFsbCBwYXJ0aWNpcGFudHMgYXJlIGluY2x1ZGVkKQ0KIycgQHBhcmFtIGNvbXBsaWFuY2UudHlwZSA9IGNoYXJhY3RlciB2YWx1ZSBkZXRlcm1pbmluZyB3aGV0aGVyIHRoZSBjb21wbGlhbmNlLmN1dG9mZiB2YWx1ZSBpcyBleHByZXNzZWQgYXMgdGhlIG1pbmltdW0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucyAoY29tcGxpYW5jZS50eXBlID0gIm9icyIpIG9yIGFzIHRoZSBtaW5pbXVtIGNvbXBsaWFuY2UgcmF0ZSAoY29tcGxpYW5jZS50eXBlPSJwZXJjIikNCiMnIEBwYXJhbSBtYXgubm9icyA9IGludGVnZXIgaW5kZXhpbmcgdGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc3BvbnNlcyBwZXIgcGFydGljaXBhbnQgKHJlcXVpcmVkIHdoZW4gY29tcGxpYW5jZS50eXBlPSJwZXJjIikNCg0KaWxkLm1hbmlwIDwtIGZ1bmN0aW9uKGxvbmcsIHdpZGUsIGNsdXN0ZXIgPSAiSUQiLCBsb25nLnJlc3BUaW1lID0gIlJ1blRpbWVzdGFtcCIsDQogICAgICAgICAgICAgICAgICAgICAgcmVzcFRpbWUuZm9ybWF0ID0gIiVZLSVtLSVkICVIOiVNOiVTIiwNCiAgICAgICAgICAgICAgICAgICAgICBzY2hlZHVsZWRUaW1lcyA9IGxpc3QoYygiMDk6MTU6MDAiLCIwOTozMDowMCIsIjEwOjE1OjAwIiksICAjIGJlZXAgMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCIxMDoyMDowMCIsIjEwOjMwOjAwIiwiMTA6NDA6MDAiKSwgICMgYmVlcCAyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIjExOjUwOjAwIiwiMTI6MDA6MDAiLCIxMjoxMDowMCIpLCAgIyBiZWVwIDMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiMTM6MjA6MDAiLCIxMzozMDowMCIsIjEzOjQwOjAwIiksICAjIGJlZXAgNA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCIxNDo1MDowMCIsIjE1OjAwOjAwIiwiMTU6MTA6MDAiKSwgICMgYmVlcCA1DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIjE2OjIwOjAwIiwiMTY6MzA6MDAiLCIxNjo0MDowMCIpLCAgIyBiZWVwIDYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiMTc6NTA6MDAiLCIxODowMDowMCIsIjE4OjEwOjAwIikpLCAjIGJlZXAgNw0KICAgICAgICAgICAgICAgICAgICAgIHNjaGVkdWxlZFRpbWVzLmZvcm1hdCA9ICIlSDolTTolUyIsDQogICAgICAgICAgICAgICAgICAgICAgbG9uZy52YXJpYWJsZXMgPSBsaXN0KE5WID0gYygidjEiLCJ2MiIsInYzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURCA9IGMoImQxIiwiZDIiLCJkMyIsImQ0IiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUQyA9IGMoImMxIiwiYzIiLCJjMyIpKSwNCiAgICAgICAgICAgICAgICAgICAgICB3aWRlLnZhcmlhYmxlcyA9IGxpc3QoImdlbmRlciIsImFnZSIpLCANCiAgICAgICAgICAgICAgICAgICAgICByZW1vdmUuZmlyc3QuYmVlcCA9IEZBTFNFLCByZW1vdmUuZmlyc3QuZGF5ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgbGlzdHdpc2UuZGVsID0gRkFMU0UsIGNvbXBsaWFuY2UuY3V0b2ZmID0gTkEsIA0KICAgICAgICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UudHlwZSA9IGMoIm9icyIsInBlcmMiKSwgbWF4Lm5vYnMgPSAxOCl7DQogIA0KICAjIHJlbmFtaW5nIHZhcmlhYmxlcw0KICBjb2xuYW1lcyhsb25nKVt3aGljaChjb2xuYW1lcyhsb25nKT09Y2x1c3RlcildIDwtICJJRCIgIyBjbHVzdGVyIHZhcmlhYmxlIGluIHRoZSBsb25nIGRhdGFzZXQNCiAgY29sbmFtZXMod2lkZSlbd2hpY2goY29sbmFtZXMod2lkZSk9PWNsdXN0ZXIpXSA8LSAiSUQiICMgY2x1c3RlciB2YXJpYWJsZSBpbiB0aGUgd2lkZSBkYXRhc2V0DQogIGNvbG5hbWVzKGxvbmcpW3doaWNoKGNvbG5hbWVzKGxvbmcpPT1sb25nLnJlc3BUaW1lKV0gPC0gInJlc3BUaW1lIiAjIHRpbWUgdmFyaWFibGUgaW4gdGhlIGxvbmcgZGF0YXNldA0KICANCiAgIyAxKSBkYXRhIHJlYWRpbmcgKHJlbW92aW5nIHVudXNlZnVsIGNvbHVtbnMpLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBsb25nIDwtIGxvbmdbLHdoaWNoKGNvbG5hbWVzKGxvbmcpICVpbiUgYygiSUQiLCJyZXNwVGltZSIsYXMuY2hhcmFjdGVyKHVubGlzdChsb25nLnZhcmlhYmxlcykpKSldDQogIHdpZGUgPC0gd2lkZVssd2hpY2goY29sbmFtZXMod2lkZSkgJWluJSBjKCJJRCIsYXMuY2hhcmFjdGVyKHVubGlzdCh3aWRlLnZhcmlhYmxlcykpKSldDQogIA0KICAjIHByaW50IGluZm8NCiAgY2F0KCJEYXRhIHByZS1wcm9jZXNzaW5nLi4uXG5cbiIpDQogIA0KICAjIDIpIHRlbXBvcmFsIHN5bmNocm9uaXphdGlvbi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NCiAgbG9uZyR0aW1lIDwtIGFzLlBPU0lYY3Qoc3RyZnRpbWUoYXMuUE9TSVhjdChsb25nJHJlc3BUaW1lLCBmb3JtYXQ9IiVZLSVtLSVkICVIOiVNOiVTIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdD0iJUg6JU06JVMiKSxmb3JtYXQ9IiVIOiVNOiVTIikgIyByZXNwIHRpbWUNCiAgbG9uZyRkYXRlIDwtIGFzLkRhdGUoc3Vic3RyKGxvbmckcmVzcFRpbWUsMSwxMCksZm9ybWF0PSIlWS0lbS0lZCIpICMgcmVzcCBkYXRlIHdpdGhvdXQgdGltZQ0KICAjIGNyZWF0aW5nICdkYXknIHZhcmlhYmxlIGJhc2Ugb24gcmVzcG9uc2UgZGF0ZXMNCiAgbG9uZyRkYXkgPC0gMSANCiAgZm9yKGkgaW4gMjpucm93KGxvbmcpKXsgaWYobG9uZ1tpLCJJRCJdICE9IGxvbmdbaS0xLCJJRCJdKXsgbG9uZ1tpLCJkYXkiXSA8LSAxIH0gZWxzZSB7DQogICAgICBpZighaXMubmEobG9uZ1tpLCJkYXRlIl0pICYgIWlzLm5hKGxvbmdbaS0xLCJkYXRlIl0pICYgDQogICAgICAgICBhcy5QT1NJWGx0KGxvbmdbaSwiZGF0ZSJdKSR3ZGF5ICE9IGFzLlBPU0lYbHQobG9uZ1tpLTEsImRhdGUiXSkkd2RheSl7DQogICAgICAgIGxvbmdbaSwiZGF5Il0gPC0gbG9uZ1tpLTEsImRheSJdICsgMSB9IGVsc2V7IGxvbmdbaSwiZGF5Il0gPC0gbG9uZ1tpLTEsImRheSJdIH19fQ0KICAjIGNyZWF0aW5nICdiZWVwJyB2YXJpYWJsZSBiYXNlZCBvbiBzY2hlZHVsZWQgdGltZXN0YW1wcw0KICBpZighaXMubmEoc2NoZWR1bGVkVGltZXNbWzFdXVsxXSkpeyBjZW50cmFsLnRpbWVzIDwtIGMoKSAjIHNhdmluZyB2ZWN0b3Igb2YgY2VudHJhbCB0aW1lcw0KICAgIGZvcihpIGluIDE6bGVuZ3RoKHNjaGVkdWxlZFRpbWVzKSl7ICMgYXNzaWduIGJlZXAgdmFsdWUgZGVwZW5kaW5nIG9uIGVhY2ggY291cGxlIG9mIG1pbi1tYXgNCiAgICAgIGxvbmdbIWlzLm5hKGxvbmckdGltZSkgJiANCiAgICAgICAgICAgICBsb25nJHRpbWUgPiAoYXMuUE9TSVhjdChzY2hlZHVsZWRUaW1lc1tbaV1dWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSBzY2hlZHVsZWRUaW1lcy5mb3JtYXQpIC0gMTAqNjApICYgDQogICAgICAgICAgICBsb25nJHRpbWUgPCAoYXMuUE9TSVhjdChzY2hlZHVsZWRUaW1lc1tbaV1dWzNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9IHNjaGVkdWxlZFRpbWVzLmZvcm1hdCkgKyAxMCo2MCksImJlZXAiXSA8LSBpIA0KICAgICAgY2VudHJhbC50aW1lcyA8LSBjKGNlbnRyYWwudGltZXMsIHNjaGVkdWxlZFRpbWVzW1tpXV1bMl0pIH0NCiAgIyB3aGVuIHRpbWUgaXMgb3V0c2lkZSB0aGUgc2NoZWR1bGVkIGludGVydmFsLCB0aGUgY2xvc2VzdCAnYmVlcCcgaXMgYXNzaWduZWQNCiAgZm9yKGkgaW4gMTpucm93KGxvbmcpKXsgcmVxdWlyZShiaXJrKSANCiAgICBpZihpcy5uYShsb25nW2ksImJlZXAiXSkgJiAhaXMubmEobG9uZ1tpLCJ0aW1lIl0pKXsgDQogICAgICBsb25nW2ksImJlZXAiXSA8LSB3aGljaC5jbG9zZXN0KGFzLlBPU0lYY3QoY2VudHJhbC50aW1lcywgZm9ybWF0ID0gc2NoZWR1bGVkVGltZXMuZm9ybWF0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9uZ1tpLCJ0aW1lIl0pIH19fQ0KICANCiAgIyAzKSBkYXRhIGNsZWFuaW5nLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICAjLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIG4xLmxvbmc8LW5yb3cobG9uZykgIyBzYXZlIE4ub2JzIGZvciBjb21wYXJpc29uDQogIG4yLmxvbmc8LWxlbmd0aCh0YWJsZShsb25nJElEKSkNCiAgbjIud2lkZTwtbGVuZ3RoKHRhYmxlKHdpZGUkSUQpKQ0KICBuIDwtIDE7IGZvcihpIGluIDE6bGVuZ3RoKHdpZGUudmFyaWFibGVzKSl7IGlmKGxlbmd0aCh3aWRlLnZhcmlhYmxlc1tpXSkgPiAxKXsgbiA8LSBuICsgMSB9fQ0KICAjIDMuMSkgcmVtb3ZpbmcgbWlzc2luZyByZXNwcyBmcm9tIHRoZSB3aWRlLWZvcm0gZGF0YXNldC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIGlmKG4gPT0gMSl7IHdpZGUgPC0gbmEub21pdCh3aWRlWyxjKCJJRCIsdW5saXN0KHdpZGUudmFyaWFibGVzKSldKSANCiAgfSBlbHNlIHsgVmFyTmFtZXMgPC0gIklEIg0KICAgIGZvcihpIGluIDE6bGVuZ3RoKHdpZGUudmFyaWFibGVzKSl7IFZhck5hbWVzIDwtIGMoVmFyTmFtZXMsbmFtZXMod2lkZS52YXJpYWJsZXNbaV0pKSB9DQogICAgd2lkZSA8LSBuYS5vbWl0KHdpZGVbLFZhck5hbWVzXSkgfQ0KICBsb25nIDwtIGxvbmdbbG9uZyRJRCAlaW4lIGFzLmNoYXJhY3Rlcih3aWRlJElEKSxdICMgcmVtb3ZpbmcgY2FzZXMgdGhhdCBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSB3aWRlIGRhdGFzZXQNCiAgbG9uZyRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGxvbmckSUQpKSAjIHJlc2V0dGluZyBsZXZlbHMNCiAgY2F0KCJEYXRhIGNsZWFuaW5nOlxuLSIsbjEubG9uZy1ucm93KGxvbmcpLCJvYnMsIixuMi5sb25nLW5sZXZlbHMobG9uZyRJRCksDQogICAgICAicGFydGljaXBhbnRzIG5vdCBpbiB0aGUgd2lkZSBkYXRhc2V0IikNCiAgIyAzLjIpIHJlbW92aW5nIGNhc2VzIHdpdGggbWlzc2luZyByZXNwb25zZXMgdG8gdGhlIGxvbmctZm9ybSBkYXRhc2V0Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBsb25nIDwtIGxvbmdbIWlzLm5hKGxvbmckcmVzcFRpbWUpLF0gDQogIGxvbmckSUQgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3Rlcihsb25nJElEKSkgIyByZXNldHRpbmcgbGV2ZWxzDQogIHdpZGUgPC0gd2lkZVt3aWRlJElEICVpbiUgbGV2ZWxzKGxvbmckSUQpLF0gIyByZW1vdmluZyBjYXNlcyB0aGF0IGFyZSBub3QgaW5jbHVkZWQgaW4gdGhlIGxvbmcgZGF0YXNldA0KICB3aWRlJElEIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIod2lkZSRJRCkpICMgcmVzZXR0aW5nIGxldmVscw0KICBjYXQoIlxuLSIsbjIud2lkZS1ucm93KHdpZGUpLCJwYXJ0aWNpcGFudHMgbm90IGluIHRoZSBsb25nIGRhdGFzZXQiKQ0KICAjIDMuMykgcmVtb3ZpbmcgZmlyc3Qgb2JzZXJ2YXRpb24gd2l0aGluIGVhY2ggZGF5Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIG4xLmxvbmc8LW5yb3cobG9uZyk7IG4yLmxvbmc8LW5sZXZlbHMobG9uZyRJRCkgIyBzYXZpbmcgc2FtcGxlIHNpemVzIGZvciBjb21wYXJpc29uDQogIGlmKGlzVFJVRShyZW1vdmUuZmlyc3QuYmVlcCkpeyANCiAgICBpZighaXMubmEoc2NoZWR1bGVkVGltZXNbWzFdXVsxXSkpeyANCiAgICAgIGxvbmcgPC0gbG9uZ1tsb25nJGJlZXAhPTEsXSAjIHJlbW92aW5nIDFzdCAnYmVlcCcgd2hlbiBzY2hlZHVsZWRUaW1lcyBhcmUgc3BlY2lmaWVkDQogICAgfSBlbHNlIHsgTE9ORyA8LSBsb25nWzAsXSAjIHJlbW92aW5nIHRoZSBmaXJzdCBkYWlseSBvYnNlcnZhdGlvbiB3aGVuIHNjaGVkdWxlZFRpbWVzIGFyZSBOT1Qgc3BlY2lmaWVkDQogICAgICBsb25nJElEZGF5IDwtIHBhc3RlKGxvbmckSUQsbG9uZyRkYXkpICMgY3JlYXRpbmcgaWRlbnRpZmllciBiYXNlZCBvbiBib3RoIElEIGFuZCBkYXkNCiAgICAgIGZvcihvYnMgaW4gbGV2ZWxzKGFzLmZhY3Rvcihsb25nJElEZGF5KSkpeyBMT05HIDwtIHJiaW5kKExPTkcsbG9uZ1tsb25nJElEZGF5ID09IG9icyxdWy0xLF0pIH0NCiAgICAgIGxvbmcgPC0gTE9ORyB9fQ0KICAjIDMuNCkgcmVtb3ZpbmcgZmlyc3QgZGF5Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIGlmKGlzVFJVRShyZW1vdmUuZmlyc3QuZGF5KSl7IGxvbmcgPC0gbG9uZ1tsb25nJGRheSE9MSxdIH0gDQogIGxvbmckSUQgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3Rlcihsb25nJElEKSkgIyByZXNldHRpbmcgbGV2ZWxzDQogIGlmKGlzVFJVRShyZW1vdmUuZmlyc3QuYmVlcCkgfCBpc1RSVUUocmVtb3ZlLmZpcnN0LmRheSkpew0KICAgIGNhdCgiXG4tIixuMS5sb25nLW5yb3cobG9uZyksIm9icywiLG4yLmxvbmctbmxldmVscyhsb25nJElEKSwNCiAgICAgICAgInBhcnRpY2lwYW50cyBmb2xsb3dpbmcgdGhlIHJlbW92YWwgb2YgdGhlIDFzdCIsDQogICAgICAgIGlmZWxzZShpc1RSVUUocmVtb3ZlLmZpcnN0LmJlZXApICYgaXNUUlVFKHJlbW92ZS5maXJzdC5kYXkpLCJkYXkgYW5kIHRoZSAxc3QgZGFpbHkgc3VydmV5IiwNCiAgICAgICAgICAgICAgIGlmZWxzZShpc1RSVUUocmVtb3ZlLmZpcnN0LmJlZXApLCJkYWlseSBzdXJ2ZXkiLCJkYXkiKSkpIH0NCiAgIyAzLjUpIGxpc3Qtd2lzZSBkZWxldGlvbi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBuMS5sb25nPC1ucm93KGxvbmcpOyBuMi5sb25nPC1ubGV2ZWxzKGxvbmckSUQpICMgc2F2aW5nIHNhbXBsZSBzaXplcyBmb3IgY29tcGFyaXNvbg0KICBpZihpc1RSVUUobGlzdHdpc2UuZGVsKSl7IGxvbmcgPC0gbmEub21pdChsb25nWyxjKCJJRCIsInJlc3BUaW1lIiwiZGF5Iixhcy5jaGFyYWN0ZXIodW5saXN0KGxvbmcudmFyaWFibGVzKSkpXSkgDQogICAgbG9uZyRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGxvbmckSUQpKSAjIHJlc2V0dGluZyBsZXZlbHMNCiAgICBjYXQoIlxuLSIsbjEubG9uZy1ucm93KGxvbmcpLCJvYnMsIixuMi5sb25nLW5sZXZlbHMobG9uZyRJRCksDQogICAgICAgICJwYXJ0aWNpcGFudHMgZm9sbG93aW5nIGxpc3Qtd2lzZSBkZWxldGlvbiIpfQ0KICAjIDMuNSkgZXhjbHVkaW5nIHBhcnRpY2lwYW50cyBiYXNlZCBvbiBjb21wbGlhbmNlIHJhdGUuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIGlmKCFpcy5uYShjb21wbGlhbmNlLmN1dG9mZikpeyBuMS5sb25nPC1ucm93KGxvbmcpOyBuMi5sb25nPC1ubGV2ZWxzKGlsZCRJRCkgIyBzYXZpbmcgc2FtcGxlIHNpemVzDQogICAgaWYoY29tcGxpYW5jZS50eXBlPT0ib2JzIil7ICMgY29tcGxpYW5jZSBiYXNlZCBvbiBvdmVyYWxsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCiAgICAgIGZvcihkYXkgaW4gbWluKGFzLmludGVnZXIobG9uZyRkYXkpKTptYXgoYXMuaW50ZWdlcihsb25nJGRheSkpKXsgDQogICAgICAgIGZvcihpIGluIDE6bnJvdyh3aWRlKSl7ICMgY29tcHV0aW5nIG5vLiBvYnMgcGVyIGRheSBhbmQgcGFydGljaXBhbnQNCiAgICAgICAgICB3aWRlW2kscGFzdGUwKCJuLmRheSIsZGF5KV0gPC0gbnJvdyhsb25nW2xvbmckSUQ9PWFzLmNoYXJhY3Rlcih3aWRlW2ksIklEIl0pICYgbG9uZyRkYXk9PWRheSxdKSB9DQogICAgICAgIGNvbG5hbWVzKHdpZGUpW25jb2wod2lkZSldIDwtICJuRGF5IiAjIHJlbmFtaW5nIGNvbHVtbg0KICAgICAgICB3aWRlIDwtIHdpZGVbd2lkZSRuRGF5ID49IGNvbXBsaWFuY2UuY3V0b2ZmLF0gIyByZW1vdmluZyBwYXJ0aWNpcGFudHMNCiAgICAgICAgY29sbmFtZXMod2lkZSlbbmNvbCh3aWRlKV0gPC0gcGFzdGUwKCJuLmRheSIsZGF5KSB9DQogICAgfSBlbHNlIGlmKGNvbXBsaWFuY2UudHlwZT09InBlcmMiKXsgIyBjb21wbGlhbmNlIGJhc2VkIG9uIHBlcmNlbnRhZ2Ugb2YgcmVzcG9uc2VzDQogICAgICAgIGZvcihpIGluIDE6bnJvdyh3aWRlKSl7IA0KICAgICAgICAgIHdpZGVbaSwiY29tcFJhdGUiXSA8LSAxMDAqbnJvdyhsb25nW2xvbmckSUQ9PWFzLmNoYXJhY3Rlcih3aWRlW2ksIklEIl0pLF0pL21heC5ub2JzIH0NCiAgICAgIHdpZGUgPC0gd2lkZVt3aWRlJGNvbXBSYXRlID49IGNvbXBsaWFuY2UuY3V0b2ZmLF0gfQ0KICAgIGxvbmcgPC0gbG9uZ1tsb25nJElEICVpbiUgYXMuY2hhcmFjdGVyKHdpZGUkSUQpLF0gIyByZW1vdmluZyB0aGUgc2FtZSBwYXJ0aWNpcGFudHMgZnJvbSB0aGUgbG9uZyBkYXRhc2V0DQogICAgbG9uZyRJRCA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGxvbmckSUQpKSAjIHJlc2V0dGluZyBsZXZlbHMNCiAgICBjYXQoIlxuLSIsbjEubG9uZy1ucm93KGxvbmcpLCJvYnMsIixuMi5sb25nLW5sZXZlbHMobG9uZyRJRCksDQogICAgICAicGFydGljaXBhbnRzIHdpdGgiLGlmZWxzZShjb21wbGlhbmNlLnR5cGU9PSJvYnMiLHBhc3RlKCJsZXNzIHRoYW4iLGNvbXBsaWFuY2UuY3V0b2ZmLCJvYnMgcGVyIGRheSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoImNvbXBsaWFuY2UgcmF0ZSA8Iixjb21wbGlhbmNlLmN1dG9mZiwiJSIpKSkgfQ0KICANCiAgIyA0KSBkYXRhIG1lcmdpbmcuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICByZXF1aXJlKHBseXIpDQogIGxvbmcgPC0gam9pbihsb25nLCB3aWRlLCBieSA9ICJJRCIpDQogIA0KICAjIDUpIGNvbXB1dGluZyBjb21wb3NpdGUgc2NvcmVzLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NCiAgIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogIG4gPC0gMTsgZm9yKGkgaW4gMTpsZW5ndGgobG9uZy52YXJpYWJsZXMpKXsgaWYobGVuZ3RoKGxvbmcudmFyaWFibGVzW1tpXV0pID4gMSl7IG4gPC0gbiArIDEgfX0NCiAgaWYobiA+IDEpew0KICAgIGZvcihpIGluIDE6bGVuZ3RoKGxvbmcudmFyaWFibGVzKSl7DQogICAgICBsb25nWyxuYW1lcyhsb25nLnZhcmlhYmxlcylbaV1dIDwtIGFwcGx5KGxvbmdbLGxvbmcudmFyaWFibGVzW1tpXV1dLDEsbWVhbixuYS5ybT1UUlVFKSB9fQ0KICANCiAgIyA2KSBkYXRhIGNlbnRlcmluZy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uDQogICMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLg0KICBpZihuID4gMSl7DQogICAgZm9yKFZhck5hbWUgaW4gbmFtZXMobG9uZy52YXJpYWJsZXMpKXsgDQogICAgICBjb2xuYW1lcyhsb25nKVtjb2xuYW1lcyhsb25nKT09VmFyTmFtZV0gPC0gIlZhck5hbWUiICMgY2hhbmdpbmcgdmFyaWFibGUgbmFtZQ0KICAgICAgY2x1c3QubWVhbnMgPC0gYWdncmVnYXRlKHggPSBsb25nJFZhck5hbWUsICMgY2x1c3RlciBtZWFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdChsb25nJElEKSwgRlVOID0gbWVhbiwgbmEucm0gPSBUUlVFKSANCiAgICAgIGNvbG5hbWVzKGNsdXN0Lm1lYW5zKSA8LSBjKCJJRCIsIlZhck5hbWViIikgIyByZW5hbWluZyB2YXJpYWJsZQ0KICAgICAgbG9uZyA8LSBqb2luKGxvbmcsIGNsdXN0Lm1lYW5zLCBieT0iSUQiKSAjIGpvaW5pbmcgY2x1c3RlciBtZWFuIHRvIGxvbmctZm9ybSBkYXRhc2V0DQogICAgICBsb25nJFZhck5hbWV3IDwtIGxvbmckVmFyTmFtZSAtIGxvbmckVmFyTmFtZWIgIyBjbHVzdGVyIG1lYW4gY2VudGVyaW5nDQogICAgICBjb2xuYW1lcyhsb25nKSA8LSBnc3ViKCJWYXJOYW1lIixWYXJOYW1lLGNvbG5hbWVzKGxvbmcpKSB9fSAjIGJhY2sgdG8gdGhlIG9yaWdpbmFsIHZhcmlhYmxlIG5hbWUNCiAgDQogICMgcHJpbnQgaW5mbw0KICBsb25nJElEIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIobG9uZyRJRCkpDQogIGNhdCgiXG5cblRvdGFsIG51bWJlciBvZiByZXRhaW5lZCBvYnNlcnZhdGlvbnMgPSIsbnJvdyhsb25nKSwiZnJvbSIsbmxldmVscyhsb25nJElEKSwicGFydGljaXBhbnRzIikNCiAgDQogICMgcmV0dXJuaW5nIGRhdGENCiAgcmV0dXJuKGxvbmcpIH0NCmBgYA0KPC9wPg0KPC9kZXRhaWxzPg0KDQo8YnI+DQoNCiMjIDMuMS4gTXVsdGl2ZXJzZSBvZiBkYXRhc2V0cw0KDQpGaXJzdCwgd2UgYXBwbHkgdGhlIGZ1bmN0aW9uIHRvIHRoZSByYXcgZGF0YXNldHMgYnkgY29uc2lkZXJpbmcgYWx0ZXJuYXRpdmUgZGF0YSBtYW5pcHVsYXRpb24gc2NlbmFyaW9zLg0KYGBge3IgfQ0KIyByZWFkaW5nIHJhdyBkYXRhc2V0cw0KbG9uZyA8LSByZWFkLmNzdigiUzVfcHJvY2Vzc2VkRGF0YS9FU01fcHJvY2Vzc2VkLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKSAjIElMRCBkYXRhc2V0DQp3aWRlIDwtIHJlYWQuY3N2KCJTNV9wcm9jZXNzZWREYXRhL1JFVFJPX3Byb2Nlc3NlZC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkgIyBwcmVsaW1pbmFyeSBxdWVzdGlvbm5haXJlDQoNCiMgc2NlbmFyaW8gIzE6IHNhbWUgc2V0dGluZ3MgYXMgYWJvdmUgKGEgcGFydCBmcm9tIHRoZSBzaW5nbGUgY2FyZWxlc3MgcmVzcG9uc2UsIHdoaWNoIGlzIHJldGFpbmVkKQ0KbTEgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgIGxpc3R3aXNlLmRlbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gMiwgY29tcGxpYW5jZS50eXBlID0gIm9icyIpDQojIHNjZW5hcmlvICMyOiBubyBkYXRhIGNsZWFuaW5nIChpLmUuLCByZXRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvYnNlcnZhdGlvbnMpDQptMiA8LSBpbGQubWFuaXAobG9uZywgd2lkZSkNCiMgc2NlbmFyaW8gIzM6IHJlbW92aW5nIGZpcnN0IHJlc3BvbnNlIHJlZ2FyZGxlc3Mgb2YgcmVzcG9uc2UgdGltZQ0KbTMgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgIGxpc3R3aXNlLmRlbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gMiwgY29tcGxpYW5jZS50eXBlID0gIm9icyIsDQogICAgICAgICAgICAgICAgc2NoZWR1bGVkVGltZXMgPSBOQSkNCiMgc2NlbmFyaW8gIzQ6IHJlbW92aW5nIGZpcnN0IGRheQ0KbTQgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5kYXkgPSBUUlVFLCAgIGxpc3R3aXNlLmRlbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gMiwgY29tcGxpYW5jZS50eXBlID0gIm9icyIpDQojIHNjZW5hcmlvICM1OiBzdHJpY3RlciBjb21wbGlhbmNlIHJhdGUgKDMrIG9ic2VydmF0aW9ucyBwZXIgZGF5KQ0KbTUgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgY29tcGxpYW5jZS5jdXRvZmYgPSAzLCBjb21wbGlhbmNlLnR5cGUgPSAib2JzIikNCiMgc2NlbmFyaW8gIzY6IGNvbXBsaWFuY2UgcmF0ZSA+IDMwJQ0KbTYgPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgY29tcGxpYW5jZS5jdXRvZmYgPSAzMCwgY29tcGxpYW5jZS50eXBlID0gInBlcmMiKQ0KIyBzY2VuYXJpbyAjNzogY29tcGxpYW5jZSByYXRlID4gNzUlDQptNyA8LSBpbGQubWFuaXAobG9uZywgd2lkZSwgDQogICAgICAgICAgICAgICAgcmVtb3ZlLmZpcnN0LmJlZXAgPSBUUlVFLCBsaXN0d2lzZS5kZWwgPSBUUlVFLCANCiAgICAgICAgICAgICAgICBjb21wbGlhbmNlLmN1dG9mZiA9IDc1LCBjb21wbGlhbmNlLnR5cGUgPSAicGVyYyIpDQojIHNjZW5hcmlvICM4OiAoNCkgYW5kICg3KQ0KbTggPC0gaWxkLm1hbmlwKGxvbmcsIHdpZGUsIA0KICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgY29tcGxpYW5jZS5jdXRvZmYgPSAzMCwgY29tcGxpYW5jZS50eXBlID0gInBlcmMiLA0KICAgICAgICAgICAgICAgIHNjaGVkdWxlZFRpbWVzID0gTkEpDQojIHNjZW5hcmlvICM5OiAoNCkgYW5kICg4KQ0KbTkgPC0gaWxkLm1hbmlwKGxvbmcsd2lkZSwgDQogICAgICAgICAgICAgICAgIHJlbW92ZS5maXJzdC5iZWVwID0gVFJVRSwgbGlzdHdpc2UuZGVsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgIGNvbXBsaWFuY2UuY3V0b2ZmID0gNzUsIGNvbXBsaWFuY2UudHlwZSA9ICJwZXJjIiwNCiAgICAgICAgICAgICAgICBzY2hlZHVsZWRUaW1lcyA9IE5BKQ0KYGBgDQoNCjxicj4NCg0KIyMgMy4yLiBSZXN1bHRzDQoNCkhlcmUsIHdlIGZpdCB0aGUgc2FtZSBtb2RlbHMgZml0dGVkIGFib3ZlIG9uIGVhY2ggZ2VuZXJhdGVkIGRhdGFzZXQsIGFuZCB3ZSBzdW1tYXJpemUgdGhlIHJlc3VsdHMgYnkgcmVwb3J0aW5nIHRoZSB2YWx1ZSBgVFJVRWAgKGkuZS4sIHNpZ25pZmljYW50KSBvciBgRkFMU0VgIChpLmUuLCBub24tc2lnbmlmaWNhbnQpIGZvciBlYWNoIG1haW4gYW5kIGludGVyYWN0aXZlIGVmZmVjdCBvZiBpbnRlcmVzdC4gV2UgY2FuIHNlZSB0aGF0IHRoZSByZXN1bHRzIG9idGFpbmVkIGFib3ZlIGFyZSBxdWl0ZSByb2J1c3QgYWNyb3NzIHRoZSBjb25zaWRlcmVkIHNjZW5hcmlvcy4gU3BlY2lmaWNhbGx5LCB0aGUgbW9zdCByb2J1c3QgZmluZGluZ3MgY29uY2VybiB0aGUgbmVnYXRpdmUgbGV2ZWwtMSBlZmZlY3Qgb2YgdGFzayBjb250cm9sIChzaWduaWZpY2FudCBhY3Jvc3MgYWxsIHNjZW5hcmlvcykgYW5kIHRoZSBsYWNrIG9mIGxldmVsLTEgaW50ZXJhY3Rpb24gKG5vbi1zaWduaWZpY2FudCBhY3Jvc3MgYWxsIHNjZW5hcmlvcykuIFRoZSBtYWluIGVmZmVjdCBvZiB0YXNrIGRlbWFuZHMgZXN0aW1hdGVkIGJ5IE1vZGVsIDEgaXMgYWxzbyBxdWl0ZSByb2J1c3QsIGJlaW5nIG5vbi1zaWduaWZpY2FudCBvbmx5IGluIG9uZSBjYXNlIChpLmUuLCByZW1vdmFsIG9mIHRoZSBmaXJzdCBkYXkpLiBGaW5hbGx5LCB0aGUgbWFpbiBhbmQgaW50ZXJhY3RpdmUgZWZmZWN0cyBlc3RpbWF0ZWQgYnkgTW9kZWwgMiBiZWNvbWUgbm9uLXNpZ25pZmljYW50IG9ubHkgd2hlbiBhIGNvbXBsaWFuY2UgcmF0ZSBvZiA3MCUgaXMgYXBwbGllZCwgeWV0IHRoZSByZXN1bHRpbmcgZGF0YXNldHMgYXJlIHZlcnkgc21hbGwgKGkuZS4sICpuMSogcmFuZ2luZyBmcm9tIDIxNiB0byAzNTgsICpuMiogcmFuZ2luZyBmcm9tIDE0IHRvIDIzKS4gT3ZlcmFsbCwgc3VjaCByb2J1c3RuZXNzIGNoZWNrcyAqKnN1cHBvcnQgdGhlIGdlbmVyYWxpemFiaWxpdHkgb2Ygb3VyIGZpbmRpbmdzKiouDQpgYGB7ciB9DQojIG11bHRpdmVyc2Ugb2YgZGF0YXNldHMgYXMgYSBsaXN0DQptIDwtIGxpc3QobTEsbTIsbTMsbTQsbTUsbTYsbTcsbTgsbTkpDQoNCiMgZGF0YS5mcmFtZSBvZiByZXN1bHRzIHRvIGJlIGZpbGxlZA0Kb3V0IDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3c9MCxuY29sPTgpKQ0KY29sbmFtZXMob3V0KSA8LSBjKCJOMSIsIk4yIiwibTEuVER3IiwibTEuVEN3IiwibTEuaW50IiwibTIuVER3IiwibTIuVENiIiwibTIuaW50IikNCg0KIyBmaXR0aW5nIG1vZGVscyBvbiBlYWNoIGRhdGFzZXQNCmZvcihpIGluIDE6bGVuZ3RoKG0pKXsNCiAgZml0MSA8LSBsbWVyKE5WIH4gVER3ICogVEN3ICsgYWdlICsgZ2VuZGVyICsgKFREd3xJRCksIGRhdGEgPSBtW1tpXV0pDQogIGZpdDIgPC0gbG1lcihOViB+IFREdyAqIFRDYiArIGFnZSArIGdlbmRlciArIChURHd8SUQpLCBkYXRhID0gbVtbaV1dKQ0KICBvdXQgPC0gcmJpbmQob3V0LCAjIGV4dHJhY3RpbmcgcmVzdWx0cyAoaS5lLiwgZWZmZWN0cyBtYXJrZWQgYXMgVFJVRSBpZiBDb2VmZi4vU0UgPiAxLjk2LCBGQUxTRSBvdGhlcndpc2UpDQogICAgICAgICAgICAgICBkYXRhLmZyYW1lKE4xID0gbGVuZ3RoKHJlc2lkdWFscyhmaXQxKSksIE4yID0gYXMuaW50ZWdlcihzdW1tYXJ5KGZpdDEpJG5ncnBzKSwgIyBzYW1wbGUgc2l6ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbTEuVER3PWFicyhzdW1tYXJ5KGZpdDEpJGNvZWZmaWNpZW50c1syLDNdKT4xLjk2LCAjIG1vZGVsIDEgbWFpbiBlZmZlY3RzDQogICAgICAgICAgICAgICAgICAgICAgICAgIG0xLlRDdz1hYnMoc3VtbWFyeShmaXQxKSRjb2VmZmljaWVudHNbMywzXSk+MS45NiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIG0xLmludD1hYnMoc3VtbWFyeShmaXQxKSRjb2VmZmljaWVudHNbNiwzXSk+MS45NiwgIyBtb2RlbCAxIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAgIG0yLlREdz1hYnMoc3VtbWFyeShmaXQyKSRjb2VmZmljaWVudHNbMiwzXSk+MS45NiwgIyBtb2RlbCAyIG1haW4gZWZmZWN0cw0KICAgICAgICAgICAgICAgICAgICAgICAgICBtMi5UQ2I9YWJzKHN1bW1hcnkoZml0MikkY29lZmZpY2llbnRzWzMsM10pPjEuOTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtMi5pbnQ9YWJzKHN1bW1hcnkoZml0MikkY29lZmZpY2llbnRzWzYsM10pPjEuOTYpKSB9ICMgbW9kZWwgMiBpbnRlcmFjdGlvbg0KY2JpbmQoZGF0YT1jKCIxLiBPcmlnaW5hbCIsIjIuIEFsbCBpbiIsIjMuIDFzdCByZXNwIG91dCIsIjQuIDFzdCBkYXkgb3V0IiwgIyBwcmludGluZyByZXN1bHRzDQogICAgICAgICAgICAgIjUuIDMrIG9icy9kYXkiLCI2LiAzMCUgY29tcGwiLCI3LiA3MCUgY29tcGwiLCI4LiAoNCkgJiAoNykiLCIxOS4gKDQpICYgKDgpIiksb3V0KSAjIG5hbWluZyBzY2VuYXJpb3MNCmBgYA0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7I3JlZn0NCg0KLSBDYXVnaGxpbiwgRC4gRS4gKDIwMjMpLiAqUiBmb3IgSFI6IEFuIEludHJvZHVjdGlvbiB0byBIdW1hbiBSZXNvdXJjZSBBbmFseXRpY3MgVXNpbmcgUiouIGh0dHBzOi8vcmZvcmhyLmNvbS9pbmRleC5odG1sI2hyYWdyb3d0aCANCi0gQ3JhbmZvcmQsIEouIEEuLCBTaHJvdXQsIFAuIEUuLCBJaWRhLCBNLiwgUmFmYWVsaSwgRS4sIFlpcCwgVC4sICYgQm9sZ2VyLCBOLiAoMjAwNikuIEEgUHJvY2VkdXJlIGZvciBFdmFsdWF0aW5nIFNlbnNpdGl2aXR5IHRvIFdpdGhpbi1QZXJzb24gQ2hhbmdlOiBDYW4gTW9vZCBNZWFzdXJlcyBpbiBEaWFyeSBTdHVkaWVzIERldGVjdCBDaGFuZ2UgUmVsaWFibHk/ICpQZXJzb25hbGl0eSBhbmQgU29jaWFsIFBzeWNob2xvZ3kgQnVsbGV0aW4sIDMyKig3KSwgOTE3LS05MjkuIDxodHRwczovL2RvaS5vcmcvMTAuMTE3Ny8wMTQ2MTY3MjA2Mjg3NzIxPg0KDQotIEN1cnJhbiwgUC4gRy4gKDIwMTYpLiBNZXRob2RzIGZvciB0aGUgZGV0ZWN0aW9uIG9mIGNhcmVsZXNzbHkgaW52YWxpZCByZXNwb25zZXMgaW4gc3VydmV5IGRhdGEuIEpvdXJuYWwgb2YgRXhwZXJpbWVudGFsIFNvY2lhbCBQc3ljaG9sb2d5LCA2NiwgNC0xOS4gPGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouamVzcC4yMDE1LjA3LjAwNj4NCg0KLSBFaW5zcHJ1Y2gsIEUuIEwuICgyMDIyKS4gKkFuIEludHJvZHVjdG9yeSBHdWlkZSB0byBSOiBFYXNpbmcgdGhlIExlYXJuaW5nIEN1cnZlKi4gR3VpbGZvcmQgUHJlc3MuDQoNCi0gR2VsZGhvZiwgRy4gSi4sIFByZWFjaGVyLCBLLiBKLiwgJiBaeXBodXIsIE0uIEouICgyMDE0KS4gUmVsaWFiaWxpdHkgZXN0aW1hdGlvbiBpbiBhIG11bHRpbGV2ZWwgY29uZmlybWF0b3J5IGZhY3RvciBhbmFseXNpcyBmcmFtZXdvcmsuICpQc3ljaG9sb2dpY2FsIE1ldGhvZHMsIDE5KigxKSwgNzLigJM5MS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzcvYTAwMzIxMzgNCg0KLSBXaWNraGFtLCBILiwgQ2V0aW5rYXlhLVJ1bmRlbCwgTS4sICYgR3JvbGVtdW5kICBHLiAoMjAyMykuIFIgZm9yIERhdGEgU2NpZW5jZTogSW1wb3J0LCBUaWR5LCBUcmFuc2Zvcm0sIFZpc3VhbGl6ZSwgYW5kIE1vZGVsICgybmQgRWQuKS4gT+KAmVJlaWxseS4gQXZhaWxhYmxlIGF0IGh0dHBzOi8vcjRkcy5oYWRsZXkubnovDQoNCi0gSGFtYWtlciwgRS4gTC4sICYgR3Jhc21hbiwgUi4gUC4gUC4gUC4gKDIwMTUpLiBUbyBjZW50ZXIgb3Igbm90IHRvIGNlbnRlcj8gSW52ZXN0aWdhdGluZyBpbmVydGlhIHdpdGggYSBtdWx0aWxldmVsIGF1dG9yZWdyZXNzaXZlIG1vZGVsLiBGcm9udGllcnMgaW4gUHN5Y2hvbG9neSwgNS4gaHR0cHM6Ly9kb2kub3JnLzEwLjMzODkvZnBzeWcuMjAxNC4wMTQ5MiANCg0KLSBIdWFuZywgSi4gTC4sIEN1cnJhbiwgUC4gRy4sIEtlZW5leSwgSi4sIFBvcG9za2ksIEUuIE0uLCAmIERlU2hvbiwgUi4gUC4gKDIwMTIpLiBEZXRlY3RpbmcgYW5kIGRldGVycmluZyBpbnN1ZmZpY2llbnQgZWZmb3J0IHJlc3BvbmRpbmcgdG8gc3VydmV5cy4gSm91cm5hbCBvZiBCdXNpbmVzcyBhbmQgUHN5Y2hvbG9neSwgMjcsIDk5LTExNC4gPGh0dHBzOi8vZG9pLm9yZy8xMC4xMDA3L3MxMDg2OS0wMTEtOTIzMS04Pg0KDQotIEphaywgUy4sICYgSm9yZ2Vuc2VuLCBULiBELiAoMjAxNykuIFJlbGF0aW5nIG1lYXN1cmVtZW50IGludmFyaWFuY2UsIGNyb3NzLWxldmVsIGludmFyaWFuY2UsIGFuZCBtdWx0aWxldmVsIHJlbGlhYmlsaXR5LiAqRnJvbnRpZXJzIGluIHBzeWNob2xvZ3ksIDgqLCAxNjQwLiA8aHR0cHM6Ly9kb2kub3JnLzEwLjMzODkvZnBzeWcuMjAxNy4wMTY0MD4NCg0KLSBLYWJhY29mZiwgUi4gSS4gKDIwMjIpLiAqUiBpbiBBY3Rpb246IERhdGEgYW5hbHlzaXMgYW5kIGdyYXBoaWNzIHdpdGggUiBhbmQgVGlkeXZlcnNlKiAoM3JkLiBFZCkuIE1hbm5pbmcuDQoNCi0gS2FyYXNlaywgUi4gQS4gKDE5NzkpLiBKb2IgRGVtYW5kcywgSm9iIERlY2lzaW9uIExhdGl0dWRlLCBhbmQgTWVudGFsIFN0cmFpbjogSW1wbGljYXRpb25zIGZvciBKb2IgUmVkZXNpZ24uICpBZG1pbmlzdHJhdGl2ZSBTY2llbmNlIFF1YXJ0ZXJseSwgMjQqKDIpLCAyODUtLTMwOC4gPGh0dHBzOi8vZG9pLm9yZy8xMC4yMzA3LzIzOTI0OTg+DQoNCi0gTWNOZWlzaCwgRC4gKDIwMTcpLiBTbWFsbCBTYW1wbGUgTWV0aG9kcyBmb3IgTXVsdGlsZXZlbCBNb2RlbGluZzogQSBDb2xsb3F1aWFsIEVsdWNpZGF0aW9uIG9mIFJFTUwgYW5kIHRoZSBLZW53YXJkLVJvZ2VyIENvcnJlY3Rpb24uICpNdWx0aXZhcmlhdGUgQmVoYXZpb3JhbCBSZXNlYXJjaCwgNTIqKDUpLCA2NjHigJM2NzAuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzAwMjczMTcxLjIwMTcuMTM0NDUzOA0KDQotIE1jTnVsdHksIEsuICgyMDIyKS4gKkhhbmRib29rIG9mIFJlZ3Jlc3Npb24gTW9kZWxpbmcgaW4gUGVvcGxlIEFuYWx5dGljczogV2l0aCBFeGFtcGxlcyBpbiBSLCBQeXRob24gYW5kIEp1bGlhKi4gQ1JDIFByZXNzLiBGcmVlbHkgYXZhaWxhYmxlIGF0IGh0dHBzOi8vcGVvcGxlYW5hbHl0aWNzLXJlZ3Jlc3Npb24tYm9vay5vcmcvaW5kZXguaHRtbA0KDQotIE1lbmdoaW5pLCBMLiwgUGFzdG9yZSwgTS4sICYgQmFsZHVjY2ksIEMuICgyMDIzKS4gV29ya3BsYWNlIFN0cmVzcyBpbiBSZWFsIFRpbWU6IFRocmVlIFBhcnNpbW9uaW91cyBTY2FsZXMgZm9yIHRoZSBFeHBlcmllbmNlIFNhbXBsaW5nIE1lYXN1cmVtZW50IG9mIFN0cmVzc29ycyBhbmQgU3RyYWluIGF0IFdvcmsuICpFdXJvcGVhbiBKb3VybmFsIG9mIFBzeWNob2xvZ2ljYWwgQXNzZXNzbWVudCwgMzkqKDYpLCA0MjTigJM0MzIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDI3LzEwMTUtNTc1OS9hMDAwNzI1DQoNCi0gU2hyb3V0LCBQLiBFLiwgJiBMYW5lLCBTLiBQLiAoMjAxMikuIFBzeWNob21ldHJpY3MuIEluIE0uIFIuIE1laGwgJiBULiBTLiBDb25uZXIgKEVkcy4pLCAqSGFuZGJvb2sgb2YgcmVzZWFyY2ggbWV0aG9kcyBmb3Igc3R1ZHlpbmcgZGFpbHkgbGlmZSogKHBwLiAzMDItLTMyMCkuIFRoZSBHdWlsZm9yZCBQcmVzcy4NCg0KLSBTdGFyYnVjaywgQy4gKDIwMjMpLiAqVGhlIEZ1bmRhbWVudGFscyBvZiBQZW9wbGUgQW5hbHl0aWNzIFdpdGggQXBwbGljYXRpb25zIGluIFIqLiBTcHJpbmdlci4gRnJlZWx5IGF2YWlsYWJsZSBhdCBodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2Jvb2svMTAuMTAwNy85NzgtMy0wMzEtMjg2NzQtMiANCg0KLSBXYW5nLCBMLiBQLiwgJiBNYXh3ZWxsLCBTLiBFLiAoMjAxNSkuIE9uIGRpc2FnZ3JlZ2F0aW5nIGJldHdlZW4tcGVyc29uIGFuZCB3aXRoaW4tcGVyc29uIGVmZmVjdHMgd2l0aCBsb25naXR1ZGluYWwgZGF0YSB1c2luZyBtdWx0aWxldmVsIG1vZGVscy4gKlBzeWNob2xvZ2ljYWwgTWV0aG9kcywgMjAqKDEpLCA2M+KAkzgzLiBodHRwczovL2RvaS5vcmcvMTAuMTAzNy9tZXQwMDAwMDMwIA0KDQotIFdpY2toYW0sIEguLCDDh2V0aW5rYXlhLVJ1bmRlbCwgTS4sICYgR3JvbGVtdW5kLCBHLiAoMjAyMykuICpSIGZvciBEYXRhIFNjaWVuY2U6IEltcG9ydCwgVGlkeSwgVHJhbnNmb3JtLCBWaXN1YWxpemUsIGFuZCBNb2RlbCBEYXRhKiAoMm5kIEVkLikuIE8nUmVpbGx5Lg0KDQo8YnI+DQoNCiMjIFIgcGFja2FnZXMNCg==